Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is using sizeof on a variable where a type of the same name exists well defined?

Is this well defined behaviour or is it undefined / somehow else defined which foo (data type or identifier) sizeof will be operating on ?

typedef int foo;

int main(int argc, char *argv[])
{
    char foo;
    printf ("%u\r\n", sizeof(foo));
    return 0;
}

If it is well defined, is there a way I could obtain the size of the datatype foo without declaring a variable of that type only to use sizeof on it?

like image 791
dhein Avatar asked Jul 15 '15 07:07

dhein


People also ask

Does sizeof work on variables?

The sizeof operator is the most common operator in C. It is a compile-time unary operator and used to compute the size of its operand. It returns the size of a variable. It can be applied to any data type, float type, pointer type variables.

How do you check the size of a variable of a given type?

The size of a variable depends on its type, and C++ has a very convenient operator called sizeof that tells you the size in bytes of a variable or a type. The usage of sizeof is simple. To determine the size of an integer, you invoke sizeof with parameter int (the type) as demonstrated by Listing 3.5.

What function can be used to determine the size of a variable in C?

Sizeof is a much used operator in the C or C++. It is a compile time unary operator which can be used to compute the size of its operand.

Is sizeof a keyword or operator?

The sizeof is a keyword, but it is a compile-time operator that determines the size, in bytes, of a variable or data type. The sizeof operator can be used to get the size of classes, structures, unions and any other user defined data type.


1 Answers

C does not have explicit scope resolution, so identifiers (variable names, typedef names, struct names, etc etc) can be reused and overridden when a new scope is opened. When an identifier is reused, the previous context held by that identifier is no longer visible.

In your particular code, the scope of the typedef is global, so the typedef is visible everywhere in your compile package. However, you open a new scope with the function declaration, and in that new scope you define a variable that uses the same identifier as the typedef. Now, that identifier refers to the variable instead of the type; meaning, until the scope of the variable ends (the end of the function), the typedef is completely hidden.

Recall that C is compiled linearly, so you could do something like this as a way around the shielding that occurs:

#include <stdio.h>
typedef int foo;

int main()
{
    printf ("%zu\n", sizeof (foo)); /* #1 */

    char foo;
    printf ("%zu\n", sizeof foo); /* #2 */

    return 0;
}

At point #1, note that the scope of the variable char foo has not yet opened since the compiler hasn't reached its declaration. (All the compiler will do is allocate the space on the stack for the variable).

So the usage of foo at that point is still in reference to the globally defined typedef.

By the time you hit #2, the variable is declared and the lifetime of the variable is formally started, meaning the identifier is now in use for a different entity. It shields the current block scope (started by the function declaration) from the global definition of foo.

This is well-document behavior; there is a draft of the C standard up online, but the published standard has to be purchased. The draft says in section 6.2.1:

If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope. source

Note that this isn't magical or anything...this is all done at compile-time. The compiler has a table of identifiers and the things they reference, and new scopes create new tables for these. It so happens that at point #1 in the code above, the compiler hasn't yet populated the table with the new char foo (this is due to the linear compilation). So when it translates the first printf line, it looks through all the active scopes to find the identifier foo, and sees the typedef, and uses that. At the second printf, it looks through all the active scopes and finds a more recent use of the identifier foo and uses that.

like image 59
Purag Avatar answered Oct 11 '22 15:10

Purag