Dlaczego sizeof (x++) nie zwiększa x?

Oto kod skompilowany w dev C++ windows:

#include <stdio.h>

int main() {
    int x = 5;
    printf("%d and ", sizeof(x++)); // note 1
    printf("%d\n", x); // note 2
    return 0;
}

Oczekuję, że x będzie 6 po wykonaniuUwaga 1 . Jednak wyjście to:

4 and 5

Czy ktoś może wyjaśnić dlaczego x nie zwiększa się po Uwaga 1 ?

 476
Author: razlebe, 2011-11-22

8 answers

Z C99 Standard (nacisk jest mój)

6.5.3.4/2

Operator sizeof otrzymuje rozmiar (w bajtach) swojego operandu, który może być wyrażeniem lub nazwą typu w nawiasie. Wielkość zależy od typu operandu. Wynikiem jest liczba całkowita. Jeśli Typ operandu jest typem tablicy o zmiennej długości, operand jest oceniany; w przeciwnym razie operand nie jest oceniany, a wynikiem jest liczba całkowita stała.

 506
Author: pmg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-24 09:05:51

sizeof jest Operator czasu kompilacji, Tak więc w czasie kompilacji sizeof i jej operand zostają zastąpione przez wartość wyniku. Parametr nie jest oceniany (z wyjątkiem sytuacji, gdy jest to tablica o zmiennej długości); liczy się tylko Typ wyniku.

short func(short x) {  // this function never gets called !!
   printf("%d", x);    // this print never happens
   return x;
}

int main() {
   printf("%d", sizeof(func(3))); // all that matters to sizeof is the 
                                  // return type of the function.
   return 0;
}

Wyjście:

2

Jako short zajmuje 2 bajty na mojej maszynie.

Zmiana typu zwracanej funkcji na double:

double func(short x) {
// rest all same

Da 8 jako wyjście.

 177
Author: codaddict,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-23 10:50:00

sizeof(foo) bardzo stara się odkryć rozmiar wyrażenia w czasie kompilacji:

6.5.3.4:

Operator sizeof otrzymuje rozmiar (w bajtach) swojego operandu, który może być wyrażenie lub nazwa typu w nawiasie. Wielkość zależy od rodzaju operand. Wynikiem jest liczba całkowita. Jeżeli typem operandu jest tablica o zmiennej długości Typ, operand jest oceniany; w przeciwnym razie operand nie jest oceniany, a wynikiem jest liczba całkowita stała.

W skrócie: tablice o zmiennej długości, uruchamiane w czasie wykonywania. (Uwaga: tablice o zmiennej długości są specyficzną cechą -- a nie tablicami przypisanymi do malloc(3).) W przeciwnym razie obliczany jest tylko Typ wyrażenia i to w czasie kompilacji.

 46
Author: sarnold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-22 11:13:53

sizeof jest operatorem wbudowanym w czas kompilacji i jest , a nie funkcją. Staje się to bardzo jasne w przypadkach, w których można go użyć bez nawiasu:

(sizeof x)  //this also works
 33
Author: hugomg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-23 12:22:59

Uwaga

Ta odpowiedź została połączona z duplikatem, co wyjaśnia późną datę.

Oryginalny

Z wyjątkiem tablic o zmiennej długości sizeof Nie ocenia swoich argumentów. Możemy to zobaczyć w sekcji Projekt C99 standard 6.5.3.4 Operator sizeof paragraf 2 który mówi:

Operator sizeof otrzymuje rozmiar (w bajtach) swojego operandu, który może być wyrażenie lub nazwa typu w nawiasie. Wielkość zależy od rodzaju operand. Wynikiem jest liczba całkowita. jeśli Typ operandu jest tablicą o zmiennej długości Typ, operand jest oceniany; w przeciwnym razie operand nie jest oceniany, a wynikiem jest stała całkowita.

A comment (now removed ) asked if something like this would evaluate at run-time:

sizeof( char[x++]  ) ;

I rzeczywiście, coś takiego też by zadziałało (Zobacz też oboje żyją):

sizeof( char[func()]  ) ;

Ponieważ obie są tablicami o zmiennej długości. Chociaż, nie widzę wiele praktycznego zastosowania w żadnym z nich.

Uwaga, tablice o zmiennej długości są objęte sekcją draft C99 standard 6.7.5.2 Tabela 4:

[...] Jeżeli rozmiar jest wyrażeniem o stałej całkowitej, A Typ elementu ma znaną stałą wielkość, to typ tablicy nie jest typem tablicy o zmiennej długości; w przeciwnym razie typ tablicy jest typem tablicy o zmiennej długości.

Update

W C11 odpowiedź zmienia się dla przypadku VLA, w niektórych przypadkach nie jest określone, czy wyrażenie size Jest oceniane, czy nie. Z sekcji 6.7.6.2 array declarators {[20] } which says:

[...] Gdzie wyrażenie size Jest częścią operandu sizeof operator i zmiana wartości wyrażenia size Nie wpływ na wynik operatora, nie jest określone, czy obliczane jest wyrażenie rozmiaru.

Na przykład w takim przypadku (zobacz to na żywo):

sizeof( int (*)[x++] )
 18
Author: Shafik Yaghmour,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-17 01:08:03

Ponieważ operand sizeof operatora nie jest oceniany, możesz to zrobić:

int f(); //no definition, which means we cannot call it

int main(void) {
        printf("%d", sizeof(f()) );  //no linker error
        return 0;
}

Demo Online: http://ideone.com/S8e2Y

Oznacza to, że nie musisz definiować funkcji f, jeśli jest ona używana tylko w sizeof. Technika ta jest najczęściej używana w metaprogramowaniu szablonów C++, ponieważ nawet w C++ operand sizeof nie jest oceniany.

Dlaczego to działa? Działa, ponieważ operator sizeof nie działa na wartość , zamiast tego działa na typ wyrażenia. Więc kiedy piszesz sizeof(f()), działa on na typie wyrażenia f(), a który jest niczym innym jak typem zwracanym funkcji f. Typ zwracania jest zawsze taki sam, bez względu na to, jaką wartość zwracałaby funkcja, gdyby faktycznie wykonywała.

W C++ możesz nawet to:

struct A
{
  A(); //no definition, which means we cannot create instance!
  int f(); //no definition, which means we cannot call it
};

int main() {
        std::cout << sizeof(A().f())<< std::endl;
        return 0;
}

Jednak wygląda na to, że w sizeof najpierw tworzę instancję A, pisząc A(), a następnie wywołując funkcję {[3] } Na instancji, przez pisanie A().f(), ale nic takiego się nie dzieje.

Demo: http://ideone.com/egPMi

Oto kolejny temat, który wyjaśnia kilka innych ciekawych właściwości sizeof:

 10
Author: Nawaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:33

Wykonanie nie może nastąpić podczas kompilacji. Więc ++i/i++ nie ma mowy. Również sizeof(foo()) nie wykona funkcji, ale zwróci prawidłowy typ.

 9
Author: rakesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-27 15:33:49

sizeof() operator podaje tylko rozmiar typu danych, nie ocenia elementów wewnętrznych.

 0
Author: munna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-28 01:36:38