529

Here is the code compiled in 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;
}

I expect x to be 6 after executing note 1. However, the output is:

4 and 5

Can anyone explain why x does not increment after note 1?

razlebe
  • 7,134
  • 6
  • 42
  • 57
Neigyl R. Noval
  • 6,018
  • 4
  • 27
  • 45
  • 41
    I'd note that DevC++ uses a very old outdated compiler, you may want to upgrade to a newer IDE, e.g. Codeblocks Eclipse or Visual Studio – Tom J Nowell Nov 22 '11 at 13:55
  • `printf("%d and ", sizeof(x++)); // note 1` causes UB, why do you expect any meaningful output? Please read the `printf()` manpage or the C standard sections about `printf()`/ `fprintf()`. – 12431234123412341234123 Aug 02 '21 at 11:57

10 Answers10

562

From the C99 Standard (the emphasis is mine)

6.5.3.4/2

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
pmg
  • 106,608
  • 13
  • 126
  • 198
  • 8
    what do you mean by variable length array type? That does mean the operand is an array? The code in this case is not an array. Can you clear things up for me? – Neigyl R. Noval Nov 22 '11 at 11:19
  • 43
    A variable length array is an array declared with the size being a value unknown during compilation, for instance if you read `N` from stdin and make `int array[N]`. This is one of C99 features, unavailable in C++. – Kos Nov 22 '11 at 11:23
  • 21
    @LegendofCage, in particular this would mean that in something like `sizeof(int[++x])` (really, really a bad idea, anyhow) the `++` could be evaluated. – Jens Gustedt Nov 22 '11 at 12:01
  • 1
    @Joe Wreschnig: That's plain incorrect. `int[++x]` has VLA type `int[n]` (for some value of `n`). Why would you say it is `int`??? – AnT stands with Russia Dec 26 '12 at 20:19
  • This is not relevant for the code he provides, his code causes UB and that is what should be addressed. – 12431234123412341234123 Aug 02 '21 at 11:59
  • @12431234123412341234123 -- I disagree, this answer exactly addresses the question raised by OP. The point about UB IMO is irrelevant to the actual *question* in the post. – WedaPashi Jan 19 '22 at 07:16
  • This behavior is actually quite nice because it means something like sizeof(*null_ptr) won't segfault when you're trying to find the size of the type the pointer is pointing to. – Shmuel Newmark Mar 11 '22 at 07:27
196

sizeof is a compile-time operator, so at the time of compilation sizeof and its operand get replaced by the result value. The operand is not evaluated (except when it is a variable length array) at all; only the type of the result matters.

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;
}

Output:

2

as short occupies 2 bytes on my machine.

Changing the return type of the function to double:

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

will give 8 as output.

codaddict
  • 445,704
  • 82
  • 492
  • 529
  • 16
    Only sometimes - it's compile time if possible. – Martin Beckett Nov 22 '11 at 17:09
  • 1
    There's a nice benefit to compile-time resolution of the sizeof() operator when working with strings. If you have a string that is initialized as a quoted string, instead of using strlen(), where the character array comprising the string has to be scanned for the null-terminator at run time, sizeof(quoted_string) is known at compile time, and therefore at run-time. It's a small thing, but if you use the quoted string in a loop millions and millions of times, it makes a significant difference in performance. – user2548100 Jan 16 '14 at 01:17
  • 1
    If you really use it millions and millions of times in a loop, wouldn't it be much more sensible to factor the length calculation out of the loop? I surely hope you don't have millions and millions of _different_ hardcoded constants in your code. :-o – Veky Mar 29 '20 at 11:22
  • @Veky: Refactoring the length calculation out of the loop would still require tying up some kind of storage (likely a register) to hold it, which may result in an otherwise-avoidable register spill, and also require generating code to compute it. Simply having the compiler generate a constant is better in essentially every way imaginable. – supercat Oct 20 '20 at 18:36
  • I really think that whichever such trivial code transformation we can do, compiler can do too. But maybe I'm mistaken. – Veky Oct 21 '20 at 01:42
  • Your code causes UB just like the ones from the OP: `printf("%d", sizeof(func(3)));` This lines causes UB. When you enable compiler warnings it is likely that the compiler warns you about this line. – 12431234123412341234123 Aug 02 '21 at 12:00
  • Re "*`sizeof` is a compile-time operator*", No, Example: `printf( "%zu\n", sizeof( int[ printf("!") ] ) );` prints something like `!4` – ikegami Feb 10 '23 at 14:45
51

sizeof(foo) tries really hard to discover the size of an expression at compile time:

6.5.3.4:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

In short: variable length arrays, run at runtime. (Note: Variable Length Arrays are a specific feature -- not arrays allocated with malloc(3).) Otherwise, only the type of the expression is computed, and that at compile time.

sarnold
  • 102,305
  • 22
  • 181
  • 238
36

sizeof is a compile-time builtin operator and is not a function. This becomes very clear in the cases you can use it without the parenthesis:

(sizeof x)  //this also works
hugomg
  • 68,213
  • 24
  • 160
  • 246
  • 1
    But how is this an answer to the question? – Sebastian Mach Nov 23 '11 at 12:15
  • 5
    @phresnel: This is just to make it clear that sizeof is "weird" and is not subject to the rules of normal functions. I edited the post anyway to remove the possible confusion with normal runtime operators like (+) and (-) – hugomg Nov 23 '11 at 12:25
  • 1
    The `sizeof` operator is *not* a compile-time operator, you only have to give it a VLA to figure this out. – paxdiablo Jan 17 '20 at 09:11
25

Note

This answer was merged from a duplicate, which explains the late date.

Original

Except for variable length arrays sizeof does not evaluate its arguments. We can see this from the draft C99 standard section 6.5.3.4 The sizeof operator paragraph 2 which says:

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

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

sizeof( char[x++]  ) ;

and indeed it would, something like this would also work (See them both live):

sizeof( char[func()]  ) ;

since they are both variable length arrays. Although, I don't see much practical use in either one.

Note, variable length arrays are covered in the draft C99 standard section 6.7.5.2 Array declarators paragraph 4:

[...] If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

Update

In C11 the answer changes for the VLA case, in certain cases it is unspecified whether the size expression is evaluated or not. From section 6.7.6.2 Array declarators which says:

[...]Where a size expression is part of the operand of a sizeof operator and changing the value of the size expression would not affect the result of the operator, it is unspecified whether or not the size expression is evaluated.

For example in a case like this (see it live):

sizeof( int (*)[x++] )
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • In what way would `sizeof (char[x++]);` use the value of `x` for anything other than determining the value of the expression `x++` and the new value for `x`, both of which are normal with that operator? – supercat Feb 24 '14 at 19:21
  • @CorleyBrigman the snappy answer would be b/c the standard says so, but the reason is b/c we don't know the array size at compile time so we have to evaluate the expression at run-time. VLAs are an interesting topic, here are two posts I have on them [here](http://stackoverflow.com/questions/16588265/why-am-i-being-allowed-to-use-a-const-qualified-variable-as-an-array-size-in-c) and [here](http://stackoverflow.com/questions/21273829/does-int-size-10-yield-a-constant-expression). – Shafik Yaghmour Feb 24 '14 at 22:46
  • @Shafik - ahh, ok, i guess my confusion was I didn't realize `char[x++]` is a VLA. it looks effectively like a `char*` to my unacquainted eyes. – Corley Brigman Feb 25 '14 at 18:30
  • @CorleyBrigman I don't think a lot of people would realize that considering how questions and answers on VLA usually get higher upvoted. – Shafik Yaghmour Feb 25 '14 at 18:31
  • _"and changing the value of the size expression would not affect the result of the operator"_ - "would **not** affect"? But in case with `sizeof(char[x++])` it **would affect**. So what did they changed? Cases like `sizeof(char[1+0*x++])`? – Qwertiy Oct 23 '17 at 17:18
  • @Qwertiy: An example of a `sizeof` expression which involves a VLA, but where where evaluating a sub-expression wouldn't affect the result of the operator would be `sizeof (int(*foo[bar()]))` since the type being evaluated will always be a pointer to some kind of array, and thus would always be the same size as a pointer to the array's element type. – supercat Oct 20 '20 at 18:33
  • This answer has nothing to do with the question. The questions code causes UB and that should be addressed. The topic about evaluation in `sizeof` should be addressed in a different question where presented code does not cause UB. – 12431234123412341234123 Aug 02 '21 at 12:12
11

The execution cannot happen during compilation. So ++i/i++ will not happen. Also sizeof(foo()) will not execute the function but return correct type.

codaddict
  • 445,704
  • 82
  • 492
  • 529
rakesh
  • 1,941
  • 2
  • 16
  • 23
  • 3
    "_The execution cannot happen during compilation._" what do you mean? – curiousguy Nov 23 '11 at 00:58
  • 1
    Compilation will only create object code... The object code will be executed only when the user executes the binary. As sizeof happens at compile time assuming i++ will increment is wrong. – rakesh Nov 23 '11 at 07:35
  • "_As sizeof happens at compile time_" you mean: "as `sizeof` is a compile time constant expression"? – curiousguy Nov 23 '11 at 08:18
  • Like "#define" happens during pre-processing, similarly sizeof will happen at compile time. During compilation all the type information is available so sizeof is evaluated then and there during compilation and value is replaced. As already mentioned by @pmg "From the C99 Standard" before. – rakesh Nov 23 '11 at 09:51
  • 1
    "_sizeof will happen at compile time_" for something that is not a variable length array – curiousguy Nov 23 '11 at 23:49
11

As the operand of sizeof operator is not evaluated, you can do this:

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

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

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

That is, you don't need define the function f if it is used in sizeof only. This technique is mostly used in C++ template metaprogramming, as even in C++, the operand of sizeof is not evaluated.

Why does this work? It works because the sizeof operator doesn't operate on value, instead it operates on type of the expression. So when you write sizeof(f()), it operates on the type of the expression f(), and which is nothing but the return type of the function f. The return type is always same, no matter what value the function would return if it actually executes.

In C++, you can even this:

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;
}

Yet it looks like, in sizeof, I'm first creating an instance of A, by writing A(), and then calling the function f on the instance, by writing A().f(), but no such thing happens.

Demo : http://ideone.com/egPMi

Here is another topic which explains some other interesting properties of sizeof:

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
2

sizeof runs at compile-time, but x++ can only be evaluated at run-time. To solve this, the C++ standard dictates that the operand of sizeof is not evaluated. The C Standard says:

If the type of the operand [of sizeof] is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.

lost_in_the_source
  • 10,998
  • 9
  • 46
  • 75
0

This line here:

printf("%d and ", sizeof(x++)); // note 1

causes UB. %d Expects the type int not size_t. After you get UB the behavior is undefined including the bytes written to stdout.

If you would fix that by replacing %d with %zu or casting the value to int, but not both, you would still not increase x but that is a different problem and should be asked in a different question.

-1

sizeof() operator gives size of the data-type only, it does not evaluate inner elements.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
munna
  • 151
  • 1
  • 2
  • This is false, the ```sizeof()``` operator acts recursively, and will get the size in bytes of all elements of a container, members of a class or structure, etc. You can prove this to yourself very easily by creating a simple class with a few members and calling ```sizeof()``` on it. (However, anything in there that is a pointer it cannot see the size of - just the size of the pointer.) This happens all at compile time, as other commenters stated: expressions inside the ```sizeof()``` do not get evaluated. – Tyler Shellberg Mar 03 '20 at 22:23