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.