2010-12-11 11 views
27

Widziałem kilka makr dla długości tablicy pływających wokół:Wspólne makro długości tablicy dla C?

Od this question:

  • #define length(array) (sizeof(array)/sizeof(*(array)))
  • #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
  • #define SIZE(array, type) (sizeof(array)/(sizeof(type))

i Visual Studio _countof:

#define _countof(_Array) (sizeof(_Array)/sizeof(_Array[0])) 

Co chciałbym wiedzieć:

  1. Jaka jest różnica między tymi, używając array[0] i *array?
  2. Dlaczego powinien być preferowany?
  3. Czy różnią się w C++?

Odpowiedz

51

Oto lepsza wersja C (od projektu Chromium Google):

#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x]))/((size_t)(!(sizeof(x) % sizeof(0[x]))))) 

Poprawia wersji array[0] lub *array za pomocą 0[array], co jest równoznaczne z array[0] na zwykłym tablic, ale nie uda się skompilować jeśli array jest typu C++, który przeciąży operator[]().

Podział powoduje operację dzielenia przez zero (która powinna zostać przechwycona w czasie kompilacji, ponieważ jest to wyrażenie czasu kompilacji) dla wielu (ale nie wszystkich) sytuacji, w których wskaźnik jest przekazywany jako parametr array.

Zobacz Is there a standard function in C that would return the length of an array? więcej szczegółów.

Jest lepszym rozwiązaniem dla kodu C++. Aby uzyskać szczegółowe informacje, patrz Compile time sizeof_array without using a macro.

+8

To jest niesamowicie tajemnicze, aby chronić się przed niewłaściwym użyciem w C++, biorąc pod uwagę, że coś innego powinno być używane w C++. –

+1

Masz rację, że nie powinno to być używane w C++, ale bit zapewniający pewne bezpieczeństwo specjalnie dla C++ nie jest zbyt tajemniczy (jest to po prostu nietypowy indeks). Naprawdę tajemnicza część chroni przed niektórymi rodzajami niewłaściwego użycia w C, z których naprawdę trudno jest się wystrzegać (a makro nawet nie doskonale chroni przed tym niewłaściwym użyciem). Niewłaściwe użycie przeciwko (przekazywanie wskaźnika zamiast argumentu tablicowego) występuje często na tyle, że opłaca się mieć złożoność. Zawinięty w makro, złożoność nie jest zbyt dużym problemem (a to makro jest mniej tajemnicze niż wiele z nich spotykam). –

+0

Co to jest "0 [x]"? Możesz to zrobić? –

3

1) Nic, wartość tablicy jest wskaźnikiem do jej pierwszego elementu. Tak * array == tablica [0]
2) Preferencje osobiste
3) Nie

Zauważ, że to przyzwyczajenie praca, jeśli makro o nazwie wewnątrz funkcji gdzie matryca jest przekazywana jako parametr do funkcji. Wynika to z faktu, że obiekt tablicy przekazuje "zaniki" do wskaźnika, a nie do głębokiej kopii.

+0

Tak, to może skutecznie działać jako 'sizeof (void *)/sizeof (array [0])', która - w współczesnej rzeczywistości - czyli 8, 4, 2, 1 lub 0.;) W każdym razie - nic nie może pomóc w takiej funkcji podczas kompilacji - nigdy nie wiadomo, kto ją wywołuje i jak dużą macierz. –

15
  1. Jaka jest różnica między tymi, którzy używają macierzy [0] i * tablicy?
  2. Dlaczego powinien być preferowany?
  3. Czy różnią się w C++?

(1) Bez różnicy w C. Bez różnicy dla rzeczywistej surowej tablicy w C++.

(2) Brak podstaw technicznych do preferowania jednego lub drugiego, ale nowicjusze mogą zostać zdezorientowani przez dereferencję wskaźnika.

(3) W C++ normalnie nie używałbyś makra, ponieważ jest bardzo niebezpieczny. Jeśli przekazujesz wskaźnik zamiast rzeczywistej surowej tablicy, kod zostanie skompilowany, ale wygeneruje niepoprawny wynik. W C++ powinieneś/powinnaś użyć szablonu funkcji, np. & Hellip;

#include <stddef.h> 

typedef ptrdiff_t Size; 

template< class Type, Size n > 
Size countOf(Type (&)[n]) { return n; } 

Przyjmuje tylko rzeczywistą surową tablicę jako argument.

To część triady funkcji startOf, endOf i countOf, że jest to bardzo wygodne, aby zdefiniować tak, że mogą być stosowane zarówno do surowych tablic i standardowych kontenerach biblioteki. O ile mi wiadomo ta triada została po raz pierwszy zidentyfikowana przez Dietmara Kuehla. W C++ 0x startOf i endOf będą najprawdopodobniej dostępne jako std::begin i std::end.

Pozdrawiam & hth.,

+2

+1: Interesujące! Czy istnieje powód użycia '' zamiast ''? –

+0

Nie, nie mogę myśleć; i mogę wymyślić kilka powodów, dla których warto wybrać . –

+1

Na co trochę warto, oto moje zdanie na '' vs. '' rozumowania (uwaga: Wolę odmianę C staroświecki ja): http://stackoverflow.com/questions/2118422/scope-of -c-biblioteki-in-cxh-vs-cx/2118718 # 2118718 –