简体   繁体   中英

Behaviour of sizeof() in C (GCC)

While answering a question on sizeof(), just to see how GCC handles, I wrote the following code:

#include<stdio.h>
#include<stddef.h>
#include<limits.h>

int main(int ac, char *argv[])
{
    printf("%zu\n", sizeof(9999999999999999999999999999999999999999999999999999) );
    printf("%zu %zu \n", sizeof(int), sizeof(long long));
    return 0;
}

When compiled, GCC (4.1.2) issued a warning (as expected):

t.c:8:24: warning: integer constant is too large for its type
t.c: In function main:
t.c:8: warning: integer constant is too large for long type

And the output is:

16
4 8

How does GCC say that sizeof(9999999999999999999999999999999999999999999999999999) is 16 ?! No matter how big numnber is, it's always 16 for any integer literal greater than LLONG_MAX . On my 64-bit platform sizeof(long) is equal to sizeof(long long) .

Why does GCC behave this way? Is it some sort of undefined behaviour?!

gcc has a special non-standard type called __int128 , which is a 128bit (16 byte) integer. So sizeof(__int128) will return 16. It seams like your ultra-large constant is treated like this __int128 type. Consider the following code:

typeof(9999999999999999999999999999999999999999999999999999) (*funcptr_a)();
unsigned  __int128 (*funcptr_b)();

void dummy() {
    funcptr_a = funcptr_b;
}

If I change any of the types in the declarations of funcptr_a and funcptr_b, the assignment funcptr_a = funcptr_b; triggers a warning. I don't get a warning (gcc 4.6.3 on 64-bit Linux) for this variation, therefore I know the type of the large integer constant is unsigned __int128 .

Btw, with clang 3.0 (also 64-bit Linux) your code outputs

8
4 8

I'd say this is not undefined but an implementation defined behavior. To quote the C99 standard (Sec. 6.4.4.1, page 56):

[...] If an integer constant cannot be represented by any type in its list, it may have an extended integer type, if the extended integer type can represent its value. [..]

We can ask gcc itself:

__typeof__ (9999999999999999999999999999999999999999999999999999) var = 1;
printf("%lld\n", var);
sizes.c:10:5: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘__int128’ [-Wformat]

So gcc chooses - if supported - the type __int128 for the too large decimal constant.

What's so mysterious? That's the size of the largest type. You were warned.

All that's guaranteed by the standard is the relative sizes of the various types.

1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long)

Yes, no mystery there. Size of long and long long are both 8 bytes for GCC 64-bit.

gcc probably uses the long double type for very big numbers, for which it uses 80 bits on Intel processors. So it probably stores it in a 128-bit number: You should check sizeof(long double) .

Note: I explicitly mention gcc because Visual C++ doesn't do that (its long double type is the same as double ).

Edit: Turns out it's not long double (and according to the standard C99 6.4.4.1 alinea 6 on integer constants (page 56), isn't allowed to be). See CliffordVienna and Daniel Fischer's answers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM