2013-05-30 2 views
5

При ответе на вопрос о том, что SizeOf(), чтобы посмотреть, как GCC ручки, я написал следующий код:Поведение SizeOf() в C (GCC)

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

При компиляции, GCC (4.1.2) выдается предупреждение (как и ожидалось):

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 

И выход:

16 
4 8 

Как GCC говорят, что sizeof(9999999999999999999999999999999999999999999999999999) есть 16?! Независимо от того, насколько велика numnber, всегда 16 для любого целочисленного литерала, превышающего LLONG_MAX. На моей 64-битной платформе sizeof(long) равен sizeof(long long).

Почему GCC ведет себя так? Это какое-то неопределенное поведение ?!

+2

Кстати, 'sizeof' является ** не ** функцией, поэтому на самом деле это не должно быть написано' sizeof() ', поскольку это означает, что это так. – unwind

+0

@unwind: Вы не можете иметь 'sizeof long long', насколько я знаю. 'sizeof (T)' является общим и точным. – Puppy

+0

@unwind Я знаю, что sizeof() не является функцией, а оператором. Но я не вижу никаких проблем с упоминанием sizeof(). –

ответ

7

gcc имеет специальный нестандартный тип, называемый __int128, который является 128-битным (16-байтовым) целым числом. Таким образом, sizeof(__int128) вернется 16. Это швы, как и ваша сверхбольшая константа, обрабатываются следующим образом: __int128. Рассмотрим следующий код:

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

void dummy() { 
    funcptr_a = funcptr_b; 
} 

Если изменить любой из типов в декларациях funcptr_a и funcptr_b, назначение funcptr_a = funcptr_b; запускает предупреждение. Я не получаю предупреждение (gcc 4.6.3 на 64-разрядном Linux) для этого варианта, поэтому я знаю, что тип большой целочисленной константы unsigned __int128.

Btw, с лязгом 3.0 (также 64-битном Linux) ваш код выхода

8 
4 8 

Я бы сказал, что это не неопределенными но поведение определяется реализацией. Процитировать стандарт C99 (раздел 6.4.4.1, стр 56):

[...] Если целая константа не может быть представлена ​​любым типом в его списке, он может иметь расширенную целочисленного типа, если расширенный тип целого числа может представлять его значение. [..]

+1

Иногда можно также использовать C11 '_Generic', чтобы каким-то образом подтвердить тип, который был выведен компилятором для определенного выражения, но ваше назначение функций - хороший трюк. –

1

Что такого таинственного? Это размер самого большого типа. Вас предупредили.

Все, что гарантируется стандартом, относится к относительным размерам различных типов.

1 == SizeOf (Char) < = SizeOf (короткие) < = SizeOf (INT) < = SizeOf (длинная) < = SizeOf (длинные длинные)

+1

На моей платформе sizeof (длинный длинный) равен 8, а не 16, как показано на выводе выше. Мой вопрос о 16 приведенных для 'sizeof (9999999999999999999999999)'. –

+1

Это не отвечает на вопрос. – Medinoc

+0

Drat! Должен был удален, когда он был +3. :( –

0

Да, нет тайны там. Размер long и long long равны 8   байтам для GCC 64-бит.

0

gcc, вероятно, использует тип long double для очень больших чисел, для которого он использует 80 бит на процессорах Intel. Поэтому он, вероятно, хранит его в 128-битном номере: вы должны проверить sizeof(long double).

Примечание: Я явно упоминаю gcc, потому что Visual C++ этого не делает (его тип long double - это то же самое, что и double).

Редактировать: Оказывается, это не long double (и в соответствии со стандартом С99 6.4.4.1 Alinea 6 на целочисленных констант (стр 56), не допускается, чтобы быть). См. Ответы Клиффорда Вены и Даниэля Фишера.

+0

Потому что он слишком велик, чтобы вписываться в 'long long'. – Medinoc

+0

@KingsIndian: стандарт не требует этого. –

+2

@KingsIndian: В стандарте C99 говорится (раздел 6.4.4.1):« * Если целочисленная константа не может быть представленным любым типом в своем списке, он может иметь расширенный целочисленный тип , если расширенный целочисленный тип может представлять его значение. * «Расширенные типы определены по реализации. Вероятно, имеется флаг GCC, который может отключить такие вещи. –

6

Мы можем спросить самого GCC:

__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] 

Так ССАГПЗ, выбирает - если эта функция поддерживается - тип __int128 для слишком большого десятичной константы.

Смежные вопросы