Oto kod skompilowany w oknach dev c ++:
#include <stdio.h>
int main() {
int x = 5;
printf("%d and ", sizeof(x++)); // note 1
printf("%d\n", x); // note 2
return 0;
}
Spodziewam x
się, że będę mieć 6 lat po wykonaniu uwagi 1 . Jednak wynik jest następujący:
4 and 5
Czy ktoś może wyjaśnić, dlaczego x
nie zwiększa się po uwadze 1 ?
VLAs
której żadna z pozostałych osób tego nie robi.Odpowiedzi:
Ze standardu C99 (nacisk jest mój)
źródło
N
ze standardowego wejścia i makeint array[N]
. Jest to jedna z funkcji C99, niedostępna w C ++.sizeof(int[++x])
(naprawdę zły pomysł, tak czy inaczej)++
można to ocenić.gcc
,clang
a na ideone.com/Pf7iFsizeof
jest operatorem czasu kompilacji , więc w momencie kompilacjisizeof
i jego operand zostają zastąpione wartością wynikową. Operand nie analizowany (z wyjątkiem gdy jest to zmienna długość tablicy) wcale; liczy się tylko rodzaj wyniku.Wynik:
ponieważ
short
zajmuje 2 bajty na moim komputerze.Zmiana typu zwracanej funkcji na
double
:da
8
jako wynik.źródło
sizeof(foo)
naprawdę ciężko próbuje odkryć rozmiar wyrażenia w czasie kompilacji:6.5.3.4:
W skrócie: tablice o zmiennej długości, uruchamiane w czasie wykonywania. (Uwaga: Tablice o zmiennej długości są specyficzną cechą - nie tablice przypisane do
malloc(3)
.) W przeciwnym razie tylko typ obliczany jest wyrażenia i to w czasie kompilacji.źródło
sizeof
jest wbudowanym operatorem czasu kompilacji i nie jest funkcją. Staje się to bardzo jasne w przypadkach, gdy można go użyć bez nawiasu:źródło
sizeof
Operator nie operator kompilacji, trzeba tylko dać mu VLA do tego dojść.Uwaga
Ta odpowiedź została połączona z duplikatu, co wyjaśnia późną datę.
Oryginalny
Z wyjątkiem tablic o zmiennej długości sizeof nie ocenia swoich argumentów. Widzimy to z sekcji standardowej projektu C99.
6.5.3.4
Rozmiar operatora ust. 2, który mówi:Komentarz ( teraz usunięty ) pytał, czy coś takiego może ocenić w czasie wykonywania:
i rzeczywiście zadziałałoby, coś takiego również działałoby ( Zobacz ich obu na żywo ):
ponieważ oba są tablicami o zmiennej długości. Chociaż w żadnym z nich nie widzę praktycznego zastosowania.
Uwaga: tablice o zmiennej długości są omówione w paragrafie 4 projektu standardowej sekcji C99
6.7.5.2
deklaratorów tablic sekcji :Aktualizacja
W C11 odpowiedź zmienia się w przypadku VLA, w niektórych przypadkach nie jest określone, czy wyrażenie wielkości jest oceniane, czy nie. Z sekcji
6.7.6.2
Deklaratory tablicy, która mówi:Na przykład w takim przypadku ( zobacz na żywo ):
źródło
sizeof
jest to makro - nie tworzy kodu, ale wstępnie oblicza oczekiwaną wartość i umieszcza ją bezpośrednio w kodzie. Zauważ, że było to jedyne zachowanie do C99, ponieważ VBA nie istniały (nigdy tak naprawdę nie słyszałem o nich aż do tej odpowiedzi, wierzcie lub nie!)sizeof (char[x++]);
wartościx
do czegokolwiek innego niż określenie wartości wyrażeniax++
i nowej wartościx
, które są normalne dla tego operatora?char[x++]
to VLA.char*
dla moich nieznanych oczu wygląda to skutecznie .Ponieważ operand
sizeof
operatora nie jest oceniany, możesz to zrobić:Demo online: http://ideone.com/S8e2Y
Oznacza to, że nie musisz definiować funkcji,
f
jeśli jest używanasizeof
tylko w. Ta technika jest najczęściej używana w metaprogramowaniu szablonów C ++, podobnie jak w C ++, operandziesizeof
nie jest oceniany.Dlaczego to działa? Działa, ponieważ
sizeof
operator nie działa na wartości , zamiast tego działa na typie wyrażenia. Więc kiedy piszeszsizeof(f())
, działa na typie wyrażeniaf()
, które jest niczym innym jak zwróconym typem funkcjif
. Typ zwracany jest zawsze taki sam, bez względu na wartość, jaką zwróciłaby funkcja, gdyby faktycznie się wykonała.W C ++ możesz nawet to:
Wygląda jednak na to
sizeof
, że najpierw tworzę instancjęA
, piszącA()
, a następnie wywołując funkcjęf
w instancji, piszącA().f()
, ale nic takiego się nie dzieje.Demo: http://ideone.com/egPMi
Oto kolejny temat, który wyjaśnia kilka innych interesujących właściwości
sizeof
:źródło
Wykonanie nie może nastąpić podczas kompilacji. Tak
++i
/i++
nie nastąpi. Równieżsizeof(foo())
nie wykona funkcji, ale zwróci poprawny typ.źródło
sizeof
wyrażenie wyrażające stałą czasową kompilacji”?sizeof
działa w czasie kompilacji, alex++
można go oceniać tylko w czasie wykonywania. Aby rozwiązać ten problem, standard C ++ nakazuje, aby operandsizeof
nie był oceniany. Standard C mówi:źródło
sizeof()
operator podaje rozmiar tylko typu danych, nie ocenia elementów wewnętrznych.źródło
sizeof()
operator działa rekurencyjnie i otrzyma rozmiar w bajtach wszystkich elementów kontenera, członków klasy lub struktury itp. Możesz to bardzo łatwo udowodnić, tworząc prostą klasę z kilkoma członkami i wzywającsizeof()
to. (Jednak wszystko, co jest wskaźnikiem, którego rozmiar nie może zobaczyć - tylko rozmiar wskaźnika). Dzieje się tak podczas kompilacji, jak stwierdzili inni komentatorzy: wyrażenia wewnątrzsizeof()
nie są oceniane.