Search code examples
coperatorssizeof

How is the sizeof operator evaluated


My project demands a complete understanding of how the sizeof operator works. The C standard specification in this regard is vague and it will be dangerous to rely on my interpretations of it. I am particularly interested in when and how the sizeof ought to be processed.

  1. My previous knowledge suggested that it is a compile-time operator, which I never questioned, because I never abused sizeof too much.

    However:

    int size = 0;
    scanf("%i", &size);
    printf("%i\n", sizeof(int[size]));
    

    This for instance cannot be evaluated at compile time by any meaning.

    char c = '\0';
    char*p = &c;
    printf("%i\n", sizeof(*p));
    

    I do not remember the exact code that produces U/B, but here, *p is an actual expression (RTL unary dereference). By presumption, does it mean that sizeof(c+c) is a way to force compile-time evaluation by means of the expression or will it be optimized by the compiler?

  2. Does sizeof return a value of type int, is it a size_t (ULL on my platform), or is it implementation-defined?

  3. This article states that "The operand to sizeof cannot be a type-cast", which is incorrect. Type-casting has the same precedence as the sizeof operator, meaning in a situation where both are used, they are simply evaluated right to left. sizeof(int) * p probably does not work, because if the operand is a type in braces, this is handled first, but sizeof((int)*p) works just fine.

I am asking for a little technical elaboration on how sizeof is implemented. That can be of use to anyone who doesn't want to spread misinformation, inaccuracies or as in my case - work on a project that is directly dependent on it.


Solution

  • 1. My previous knowledge suggested that it is a compile-time operator, which I never questioned, because I never abused sizeof too much…

    C 2018 6.5.3.4 2 specifies the behavior of sizeof and says:

    … 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 your example with sizeof(int[size]), the type of int[size] is a variable length array type, so the operand is evaluated1, effectively computing the size during program execution.

    In your example with sizeof(*p), the type of *p is not a variable length array type, so the operand is not evaluated. The fact that p may point to an object of automatic storage duration that is created during program execution is irrelevant; the type of *p is known during compilation, so *p is not evaluated, and the result of sizeof is an integer constant.

    2. Does sizeof return a value of type int, is it a size_t (ULL on my platform), or is it implementation-defined.

    C 2018 6.5.3.4 5 says “The value of the result of both operators [sizeof and _Alignof] is implementation-defined, and its type (an unsigned integer type) is size_t, defined in <stddef.h> (and other headers).”

    3. This article states that "The operand to sizeof cannot be a type-cast", which is incorrect. Type-casting has the same precedence as the sizeof operator, meaning in a situation where both are used, they are simply evaluated right to left. sizeof(int) * p probably does not work, because if the operand is a type in braces, this is handled first, but sizeof((int)*p) works just fine.

    The article means the operand cannot directly be a cast-expression (C 2018 6.5.4) in the form ( type-name ) cast-expression, due to how the formal grammar of C is structured. Formally, an expression operand to sizeof is a unary-expression (6.5.3) in the grammar, and a unary-expression can, through a chain of grammar productions, be a cast-expression inside parentheses.

    Footnote

    1 We often think of a type-name (a specification of a type, such as int [size]) as more of a passive declaration than an executable statement or expression, but C 2018 6.8 4 tells us “There is also an implicit full expression in which the non-constant size expressions for a variably modified type are evaluated…”