Dlaczego sizeof int jest błędne, a sizeof (int) jest prawidłowe?


97

Wiemy, że sizeofjest to operator służący do obliczania rozmiaru dowolnego typu danych i wyrażenia, a gdy operand jest wyrażeniem, można pominąć nawiasy.

int main()
{
        int a;

        sizeof int;
        sizeof( int );
        sizeof a;
        sizeof( a );

        return 0;
}

pierwsze użycie sizeofjest złe, podczas gdy inne mają rację.

Gdy jest kompilowany przy użyciu gcc, zostanie wyświetlony następujący komunikat o błędzie:

main.c:5:9: error: expected expression before int

Moje pytanie brzmi, dlaczego standard C nie pozwala na tego rodzaju operacje. Spowoduje sizeof intjakąkolwiek dwuznaczność?


5
Zabawne jest to, że nie wszystkie wyrażenia są akceptowane bez nawiasów: spróbuj sizeof (int)a.
Fred Foo

2
@MikkelK .: OP pyta o uzasadnienie standardowych cytatów, które zna już cytaty wymienione w zaznaczonej odpowiedzi.
Alok Zapisz

2
@Lundin: sizeof +(int)ama przewagę nad *&faktyczną kompilacją ;-)
Steve Jessop

2
@SteveJessop Ach tak, to nie jest wartość l. Chociaż skompilował się w Embarcadero C ++, to dziwne. W każdym razie uważam, że właśnie znaleźliśmy zastosowanie dla jednoargumentowego operatora +! To chyba pierwszy raz w historii programowania w C :)
Lundin

2
@Lundin: Nadal musisz uważać na unary +. Na przykład, sizeof +(char)a == sizeof(int)ze względu na promocję liczb całkowitych, prawdopodobnie mniej podatne na błędy jest umieszczenie w nawiasach, jeśli w ogóle istnieje obawa o wyrażenie, którego rozmiar próbujesz przyjąć. Nie jestem więc pewien, czy posunąłbym się do nazwania tego „użytkiem”, chociaż przyznaję, że go użyłem ...
Steve Jessop

Odpowiedzi:


101

Poniższe informacje mogą być niejednoznaczne:

sizeof int * + 1

Czy tak (sizeof (int*)) + 1, czy (sizeof(int)) * (+1)?

Oczywiście język C mógł wprowadzić regułę rozwiązującą tę niejednoznaczność, ale mogę sobie wyobrazić, dlaczego to nie przeszkadzało. Przy obecnym języku specyfikator typu nigdy nie pojawia się w wyrażeniu jako „nagi”, więc nie ma potrzeby stosowania reguł do rozstrzygania, czy ta sekunda *jest częścią typu, czy operatorem arytmetycznym.

Istniejąca gramatyka rozwiązuje już potencjalną niejednoznaczność sizeof (int *) + 1. To jest (sizeof(int*))+1, nie sizeof((int*)(+1)) .

C ++ ma nieco podobny problem do rozwiązania za pomocą składni rzutowania w stylu funkcji. Możesz pisać int(0)i możesz pisać typedef int *intptr; intptr(0);, ale nie możesz pisać int*(0). W takim przypadku rozdzielczość jest taka, że ​​typ „nagi” musi być prostą nazwą typu, nie może to być po prostu żaden stary identyfikator typu, który może zawierać spacje lub końcowe znaki interpunkcyjne. Może sizeofmożna by było zdefiniować z tym samym ograniczeniem, nie jestem pewien.


1
C ++ ma new int*(X)co byłoby niejednoznaczne, gdyby C ++ nie określił, że operator new przyjmuje najdłuższy ciąg, który mógłby być typem. Więc w C ++ mogliby zrobić to samo z sizeof, jak sądzę. Ale w C ++ można powiedzieć, sizeof int()które z nich byłyby niejednoznaczne (zainicjowano typ lub wartość int?).
Johannes Schaub - litb

@ JohannesSchaub-litb: Mmm, więc być może C ++ mógłby powiedzieć, że typ jest preferowany, jeśli można go przeanalizować, w przeciwnym razie jest to wyrażenie. Niejednoznaczność zostałaby rozwiązana, ale sizeof int()byłaby źle sformułowana („nie operator()na size_t”), co, jak sądzę, byłoby niepożądane!
Steve Jessop

32

Od C99 Standard

6.5.3.4.2 operator uzyskuje rozmiar (w bajtach) jej argumentu operacji, który może być ekspresja lub nawiasach nazwa typu.
sizeof

W twoim przypadku intnie ma wyrażenia ani nazwy w nawiasach.


10
Nie rozumiem, dlaczego dostaje to 7 głosów za. Podobnie jak w przypadku trzech usuniętych odpowiedzi, po prostu powtarza regułę zamiast wyjaśniać, dlaczego reguła istnieje.
Fred Foo

8
@larsmans, tak, zgadzam się z tobą. Chociaż nadal powtarza regułę, ale przynajmniej daje kawałek autoryzacji do czytania.
Yishu Fang

3
@larsmans Jeśli zaczniemy próbować uzasadniać każdą decyzję podjętą w C99, będziemy tu przez cały rok. Cytowanie standardu jest równie dobrym sposobem na zakończenie tej dyskusji.
Perry

1
@Perry: jeśli nie podoba ci się tego rodzaju pytanie, możesz zagłosować za zamknięciem pytania jako dyskusyjne.
Fred Foo

4
Jako niepraktykujący C ++ nawet ja rozumiem tę odpowiedź, nie jestem pewien, na czym polega problem, jeśli potrafisz czytać i rozumieć angielski.
Kev

6

Istnieją dwa sposoby użycia operatora sizeof w C. Składnia jest następująca:

C11 6.5.3 Unary operators
...
sizeof unary-expression
sizeof ( type-name )

Ilekroć używasz typu jako operandu, musisz mieć nawias, zgodnie z definicją składni języka. Jeśli używasz sizeof w wyrażeniu, nie potrzebujesz nawiasów.

Standard C podaje jeden taki przykład, gdzie możesz chcieć go użyć w wyrażeniu:

sizeof array / sizeof array[0]

Jednak ze względu na spójność i aby uniknąć błędów związanych z pierwszeństwem operatorów, osobiście radziłbym zawsze używać () bez względu na sytuację.


@ JohannesSchaub-litb Zgadzam się, że nie przedstawia to żadnego uzasadnienia, w jaki sposób komisja normalizacyjna C rozumowała, kiedy określiła standard C90. Musiałbyś ich zapytać ... Odpowiada bez podania uzasadnienia, jednak C nie pozwala na to, ponieważ składnia jest taka, jak określono w 6.5.3. PO również wydawał się nieświadomy różnicy między sizeof expressioni sizeof(type), co wyjaśniono w tej odpowiedzi.
Lundin

(Dla przypomnienia, właśnie przeczytałem uzasadnienia C90 i C11 i żadne z nich nie daje żadnego wyjaśnienia.)
Lundin

Podejrzewam, że nie ma do tego koniecznego uzasadnienia, po prostu tak zdecydowali się pierwotni projektanci C. Może ułatwiło to pracę wczesnemu parserowi. Zamierzałem zamieścić odpowiedź dotyczącą faktu, że typedef i zmienne mają tę samą przestrzeń nazw, ale to nie wyklucza dopuszczenia pierwszej składni; potrzebuje tylko reguł analizy, aby powiedzieć, że preferuje zmienną, gdy nie ma parenów, preferuje typ, gdy istnieją, i można użyć dowolnej formy, gdy nazwa jest jednoznaczna. Ponieważ nie ma potrzeby tego zmieniać, komitety normalizacyjne pozostawiły to w spokoju.
Barmar
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.