1

かなり変だと思うものに出くわしました。テストプログラム

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バイトです。ただし、longlongが割り当てられるように変更すると

long long unsigned ll =  0x123456789;

コンパイル時に取得します

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

オプションを使用して64ビットビルドを強制すると、この同じテスト-m64コンパイルされます。私は何か間違ったことをしていますか、それともこれはGCCのバグですか?

4

2 に答える 2

6

これをに変更します

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

接尾辞がないと、リテラルはマシンの最大unsigned long値よりも大きくなり、C ++ 03(た​​だし、C ++ 11はありませんlong long)によると、これは未定義の動作です。これは、コンパイル時エラーを含め、何でも起こり得ることを意味します。

また、C ++ 03にないことは何の価値もないlong longので、動作が保証されているわけではなく、拡張機能に依存しています。代わりにC++11を使用しない方がよいでしょう。

于 2012-02-27T16:41:21.167 に答える
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ます。

何らかの理由で、この動作は多くの人にとって非常に直感的ではありません。そのため、同じ質問には多くのバリエーションがあります。

于 2012-02-27T17:11:58.437 に答える