2012-02-27 10 views
1

Я столкнулся с чем-то, что я думаю довольно странным. Программа испытанийприсвоение значения длинным длинным целым с использованием gcc на sparc solaris

int main(int argc, char* argv[]) 
{ 
    cout<<"hello"<<endl; 
    long unsigned l = 0x12345678; 
    long long unsigned ll = 0x12345678; 
    cout<<sizeof(l)<<endl; 
    cout<<sizeof(ll)<<endl; 
}; 

выход:

hello  
4  
8 

Никаких сюрпризов там. long int имеет размер 4 байта, а размер long long имеет размер 8 байт. Однако, когда я изменить его так, что долго долго назначается

long long unsigned ll = 0x123456789; 

во время компиляции я получаю

error: integer constant is too large for "long" type 

Теперь этот же тест делает компиляции, если я заставляю 64 битную сборку с помощью опция -m64. Я что-то делаю неправильно или это ошибка в GCC?

ответ

6

Изменить что

long long unsigned ll = 0x123456789ULL; // notice the suffix 

без суффикса, буквальный больше, чем максимальное значение unsigned long на вашей машине, и что, в соответствии с C++ 03 (но не C++ 11, который имеет long long), является неопределенным поведением. Это означает, что все может произойти, включая ошибку времени компиляции.

Не стоит ничего, что нет long long в C++ 03, поэтому он не гарантированно работает, вы полагаетесь на расширение. Вероятно, вам лучше не использовать C++ 11.

3

Дело в том, что многие люди, кажется, смотрят на строку кода, как ваш:

unsigned long long ll = 0x123456789; /* ANTI-PATTERN! Don't do this! */ 

и разума «ой, тип unsigned long long, поэтому значение unsigned long long и получает назначение», но это не так, как работает C. Литералы имеют свой собственный тип, который не зависит от контекста, в котором они используются. И тип целочисленных литералов - int.

Это та же ошибка, как, когда люди делают:

const double one_third = 1/3; /* ANTI-PATTERN! Don't do this! */ 

мышление «тип на слева double, так что это должно назначить 0.3333333 ...». Это просто (опять!), А не как работает C. Типы разделяемых литералов по-прежнему равны int, поэтому правая часть вычисляет ровно 0, которая затем преобразуется в double и сохраняется в переменной one_third.

По некоторым причинам это поведение глубоко неинтуитивно для многих людей, поэтому существует много вариантов одного и того же вопроса.