How sizeof(array) works at runtime?
Asked Answered
K

6

29

I have read that sizeof operator in C is interpreted at compile time and since at compile time compiler knows the array size and its type,sizeof is abled to compute the number of bytes occupied by array.But how is sizeof working for the following code :

 #include<stdio.h>
 #include<string.h>
 int main()
 {
    int n;
    scanf("%d",&n);
    int a[n];
    int s=sizeof(a);
    printf("%d",s);
    return 0;
 }

Here array size is not known at compile time,then how is it working properly ?

Kassel answered 9/4, 2012 at 19:2 Comment(4)
possible duplicate of Using sizeof with a dynamically allocated arrayTasman
Variable length arrays are an exception, for them, sizeof is evaluated at run time, not at compile time.Soubrette
@MДΓΓБДLL No, that one is about malloced stuff, not about VLAs.Soubrette
@MДΓΓБДLL: Your possible duplicate is dealing with a different situation (malloc(), not a VLA, variable length array).Fanchette
J
29

sizeof is always computed at compile time in C89. Since C99 and variable length arrays, it is computed at run time when a variable length array is part of the expression in the sizeof operand.

Same for the evaluation of the sizeof operand: it is not evaluated in C89 but in C99 if the operand is of variable length array type it is evaluated. For example:

int n = 5;
sizeof (int [n++]); 

// n is now 6
Jovi answered 9/4, 2012 at 19:8 Comment(5)
What does mean that int [n++]? First time I see it in C languageThorny
@TheMask int [N] is a C type name. It's an array N of int. When N is not a constant like in the answer, it's a variable length array.Jovi
@Jovi : since earlier we have studied that the expression inside sizeof operator doesn't really evaluate. ie. sizeof(n++) will leave n to 5 ( if n=5 initially ). then why value of n is changed here ?Hawks
@Hawks variable length array type operand is an exception to this rule, in this case the operand is evaluatedJovi
It's accepted, but it's not an answer to the question. Here's the real answer https://mcmap.net/q/24884/-how-sizeof-array-works-at-runtimeXerosis
C
16

Since you are applying sizeof to a variable-length array, whose size is not fully known at compile time, the compiler must generate code to do part of it at runtime.

gcc 4.6.3's high level optimizers convert the code you showed to

scanf ("%d", &n);
t12 = (long unsigned int) n;
t13 = t12 * 4;
__builtin_alloca (t13);
t16 = (unsigned int) t12;
t17 = t16 * 4;
s18 = (int) t17;
printf ("%d", s18);

Does that explain what is going on under the hood? (Don't be put off by the silly-looking number of temporary variables -- that's an artifact of the program being in static single assignment form at the point where I asked for an intermediate-code dump.)

Cocktail answered 9/4, 2012 at 19:9 Comment(3)
Put the file you want to compile in a directory by itself, then invoke gcc on it from a shell in that directory, adding -fdump-tree-all to the command line options (you probably want -S and -O2 as well). You need to isolate the file in a scratch directory because this will generate approximately 100 files of intermediate code (and that's only the first half of the optimization pipeline; -fdump-rtl-all will give you another 60ish files). You can then read through them in sequence (they're numbered)Cocktail
@TheMask (continued) The "tree" dumps are generally more useful than the "rtl" dumps unless you are trying to debug one of GCC's "back ends" (code generation for a specific architecture). You can limit the output to a specific pass of interest by saying -fdump-(tree|rtl)-PASSNAME instead of -all, where PASSNAME is the word after the number in the dump filename. See gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/… (scroll up a bit, then read from there to the end of the document) for further details.Cocktail
@TheMask ... I should probably also point you at the internals manual for GCC which explains what the intermediate representations are and how they work.Cocktail
C
8

From the C99 standard:

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.

Conley answered 9/4, 2012 at 19:11 Comment(0)
G
4

In that case, sizeof() is evaluated at run time. The compiler, because it knows that the size of a is based on the value of n at the time of the array declaration, generates code to use the appropriate value of n to return a sensible value for sizeof().

In C99, not all uses of sizeof() can be completely evaluated at compile time and reduced to a runtime constant.

Greenheart answered 9/4, 2012 at 19:6 Comment(4)
Note that the compiler might use an old value for n; for example int n = 5; char a[n]; n = 10; return sizeof(a); always returns 5, not 10.Crocodilian
@DavidHeffernan: I understand, hopefully my updated answer is more clear.Greenheart
doh I can't believe I typed "compile" when I meant "run". Too early in the morning. :)Greenheart
@greg Yes, one word can make a real difference!!Eichman
E
2

I have read that sizeof operator in C is interpreted at compile time

sizeof is determined at compile time in all cases apart from for VLAs. For a VLA, sizeof is evaluated at runtime.

Eichman answered 9/4, 2012 at 19:8 Comment(1)
Indeed (C11): "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."Pedaias
R
2

Regardless of whether sizeof is computed at compile time or runtime (or more formally speaking, whether its result is an integer constant expression), the result of sizeof is purely based on the type of its argument and not any hidden data accompanying the variable-length array itself. Of course when sizeof is applied to a variably-modified type, the generated program must keep track of that size somewhere. But it might simply recompute it if the expression was simple enough and the variables it originally derived the length from cannot have changed. Or, it could store the size of the type somewhere (essentially in a hidden local variable), but this would not be connected to the VLA object in any observable way (for example, if you pass a pointer to the first element of the VLA to another function, that pointer cannot be used to recover the VLA length).

Roshan answered 9/4, 2012 at 19:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.