2008-12-17 16 views
20

Niedawno zobaczyłem, że ktoś poleca innemu użytkownikowi użycie sizeof var zamiast sizeof (type). Zawsze myślałem, że to tylko wybór stylu. Czy jest jakaś znacząca różnica? Jako przykład, linie F i FF były uważane za lepsze niż liniach gi gg:"C" sizeof z typem lub zmienną

typedef struct _foo {} foo; 

foo *f = malloc(count * sizeof f); 
foo *g = malloc(sizeof(foo) * count); 

foo **ff = malloc(count * sizeof *ff); 
foo **gg = malloc(sizeof(foo*) * count); 

Moim zdaniem, pierwszy zestaw jest tylko kwestia stylu. Ale w drugiej parze linii dodatkową sekundę * można łatwo pomylić z mnożeniem.

+3

Masz błąd w swojej pierwszej linii 'malloc' - powinien to być' sizeof * f'. Ogólny wzór to 'somevar = malloc (count * sizeof * somevar)'. – caf

Odpowiedz

45

Jeśli zmieniony zostanie typ zmiennej, sizeof nie będzie wymagało zmiany, jeśli zmienna jest argumentem, a nie typem.

Odnośnie komentarza @ icepack: możliwość lub prawdopodobieństwo zmiany nazwy typu lub nazwy zmiennej nie jest problemem. Wyobraź sobie, że nazwa zmiennej jest używana jako argument do sizeof, a następnie później zmieniona. W najlepszym przypadku operacja zmiany nazwy zmienia wszystkie wystąpienia i nie wprowadza błędu. W najgorszym przypadku pomijany jest przypadek wielkości, a kompilator narzeka i go naprawiasz. Jeśli typ zostanie zmieniony, to znaczy, że nie ma błędów w instrukcjach sizeof.

Teraz wyobraź sobie, że typ jest argumentem sizeof. Jeśli zmienna zostanie zmieniona, nie ma innych środków niż kontrola, aby znaleźć wszystkie wielkości związane z tą zmienną. Możesz wyszukiwać, ale otrzymasz trafienia dla wszystkich niepowiązanych zastosowań sizeof tego samego typu. Jeśli zostanie pominięty, wystąpi problem ze środowiskiem wykonawczym spowodowany niedopasowaniem rozmiaru, co jest znacznie trudniejsze do znalezienia.

+1

Dla zmiennych tablicowych sizeof (array) da ci rzeczywisty rozmiar tablicy. Można go użyć do obliczenia liczby elementów sizeof (array)/sizeof (element). Zauważ, że nie zadziała dla dinamicznie przydzielonej pamięci za pomocą wskaźnika. –

+2

Nie jest to wiarygodny argument. W ten sam sposób można twierdzić, że jeśli zmienna zostanie zmieniona, rozmiar nie będzie wymagał zmiany, jeśli typem jest argument, a nie zmienną. Możliwość zmiany zależy od konkretnego projektu (w większości przypadków ani się nie zmieni, ani nie powinna się zmienić). – SomeWittyUsername

+0

Ta odpowiedź nie wydaje się być "ostatecznym" rozwiązaniem, pamiętając, że nie obejmuje przypadków, gdy logika kodu zależy raczej od typedef na określonej zmiennej. Poniżej możesz zobaczyć moją odpowiedź. – Riga

3

Linie f i ff są zdecydowanie gorsze niż g i gg. sizeof f to wielkość wskaźnika, ponieważ f jest punktem. Aby były one równoważne, musisz napisać sizeof *f (lub, dla lepszej czytelności, sizeof(*f)).

6

Oprócz tego, co mówi Steve, dodam, że sizeof nie ocenia swojego operandu. Więc możesz w nim wszystko robić. Nie tylko możesz użyć nie-jeszcze zainicjowanych zmiennych, ale możesz też wyłuskać wskaźnik zerowy, funkcje połączeń nie są zdefiniowane, ale tylko zadeklarowane i robią coś innego. Zachęcam do korzystania z wersji ekspresowej z powodów, które wyjaśnił Steve.

Weź również pod uwagę, że czasami nazwy typów są naprawdę długie i nieczytelne, wystarczy pomyśleć o wskaźnikach funkcji (szczególnie w C++). Zamiast pisać sizeof(my_long_type<weird, stuff>) po prostu robisz sizeof t.

+0

Minęły 4 lata i długi problem z nazwami w C++ został zmniejszony za pomocą 'decltype' :) – SomeWittyUsername

0

Podjęcie rozmiaru zmiennej może mieć nieoczekiwane wyniki. Gdy zmienna jest tablicą, sizeof (array) zwróci rozmiar tablicy, a nie rozmiar pojedynczego elementu lub wielkość wskaźnika. Podjęcie rozmiaru wskaźnika zwróci rozmiar wskaźnika. Ale ponieważ tablice są zazwyczaj przedstawiane jako wskaźniki, gdy są przekazywane, rzeczy mogą stać się mylące.

+1

Podczas gdy pierwsza linia wprowadza w błąd: nie ma nic nieoczekiwanego w wyniku, drugie zdanie nie występuje we wszystkich innych odpowiedziach: sizeof (array) da ci rozmiar całej tablicy, a nie elementu. Może być użyty do obliczenia liczby elementów sizeof (array)/sizeof (element) –

+0

@dribeas: yes, stąd "# define DIM (x) (sizeof (x)/sizeof (* (x))) dla różnorodność możliwych nazw makr (ARRAY_SIZE, DIMENSION, ...). –

2

Używam sizeof(type) w alokacji pamięci, ale niezmiennie sizeof(variable) przy użyciu zmiennej lokalnej lub globalnej. Niemniej jednak, w poradniku jest mądre używanie nazwy zmiennej przez cały czas.

Miałem też długą dyskusję (raczej animowaną, która trwała przez kilka dni - zakończyliśmy zgodę na różnicę w tej kwestii) o tym, czy można użyć numeru sizeof(variable), czy też musi to być sizeof variable; to znaczy, czy ma znaczenie, czy nawiasy zamykają argument do sizeof. Nigdy nie spotkałem się z kompilatorem, który testuje na temat sizeof(variable), więc wybieram jednolitość i zawsze używam nawiasów z sizeof. Mój kolega był równie nieugięty, że nawiasy nie mogą być używane ze zmiennymi; że w jakiś sposób istnieje/była cenna różnica pomiędzy notacją zi bez nawiasów.Nie jestem przekonany - nie spodziewam się, że będę przekonany.

Na zupełnie inną taktykę, kilka innych punktów o sizeof:

  • Jeśli używasz C99 i VLA - tablice o zmiennej długości - wtedy sizeof(vla) nie jest stałą czasu kompilacji. Strzec się!
  • Preprocesor C nie rozumie sizeof, co jest uciążliwe, ale logiczne.
+0

Wygląda na to, że masz tutaj inne interesujące pytanie. Rozumiem, że sizeof to rzecz kompilacji, chociaż wygląda ona i działa jak funkcja (biblioteki). Więc może chce, żeby wyglądało inaczej. Nie używam tego enuf do znaczenia. Znowu dostałem gapienia się na zrobienie "return (x);" – gbarry

+0

Najczęściej używam nawiasów wokół wartości zwracanej. Wiem, że niektórzy ludzie są przerażeni, ale to działa dla mnie. Nie jestem zdezorientowany ani z powodu powrotu, ani wielkości, które są "funkcjami". –

+1

Nienawidzę nawiasów po powrocie, głównie dlatego, że jest niepotrzebny. Posiadanie nawiasów po sizeof może pomóc w czytelności: malloc (sizeof (* f) * 10) jest dużo łatwiejszy do zrozumienia niż malloc (sizeof * f * 10). – jmucchiello

4

można zobaczyć małą różnicę między tymi:

foo **ff = malloc(count * sizeof *ff); 
foo **gg = malloc(sizeof(foo*) * count); 

..ale co jeśli przydział nie jest w pobliżu deklaracji? Gdybym natknąć się na linii jak:

ff = realloc(ff, count * sizeof *ff); 

to jestem dość pewny, że linia jest poprawne, nawet pamiętając typ ff. Jednakże, jeśli widzę tak:

ff = realloc(ff, count * sizeof(foo *)); 

wtedy mogę być nieco podejrzanie, i trzeba spojrzeć na rodzaj ff umieścić swój umysł w spoczynku.

0

Logika biznesowa definiuje twój wybór.

  1. Jeśli kod odnosi się do konkretnej zmiennej i bez tej zmiennej kodu nie ma sensu - wybierz sizeof(var)

  2. Jeśli wy oferty kodowe z zestawu zmiennych z określonego typu - wybierz sizeof(type). Zwykle potrzebujesz tego, jeśli masz typedef, który definiuje wiele zmiennych, które przetwarzasz inaczej w zależności od ich typu (np. Serializacji). Możesz nie wiedzieć, która z tych zmiennych pozostanie w przyszłych wersjach kodu, więc wybór typu jako argumentu jest logicznie poprawny. Nawet zmiana takiego typedef nie wpłynie na twoją linię sizeof.

Powiązane problemy