C / C ++で人々が行う不当な仮定を実証するための教育ツールには何が含まれていますか?


121

初心者(および中級)プログラマーがC、C ++およびそれらのプラットフォームでの不当な前提を認識して挑戦するのに役立つ、SOのための小さな教育ツールを準備したいと思います。

例:

  • 「整数は回り込む」
  • 「誰もがASCIIを持っている」
  • 「関数ポインタをvoid *に格納できます」

小さなテストプログラムをさまざまなプラットフォームで実行できると考えました。これは、SOでの経験から、多くの未経験/半経験主流の開発者が作成した「もっともらしい」仮定を実行し、さまざまなマシンでそれらが壊れる方法を記録しています。

これの目標は、何かをするのが「安全」であることを証明することではありません(実行することは不可能であり、テストが壊れた場合にのみ何でも証明します)代わりに、最も理解していない個人に最も目立たない表現を示す未定義または実装定義の動作がある場合は、別のマシンで中断します。

これを達成するために私はあなたに尋ねたいと思います:

  • このアイデアをどのように改善できますか?
  • どのテストが適切で、どのように見えるべきですか?
  • 手に入れて結果を投稿できるプラットフォームでテストを実行して、プラットフォームのデータベースを作成します。どのように違い、なぜこの違いが許容されるのでしょうか。

テストおもちゃの現在のバージョンは次のとおりです。

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <stddef.h>
int count=0;
int total=0;
void expect(const char *info, const char *expr)
{
    printf("..%s\n   but '%s' is false.\n",info,expr);
    fflush(stdout);
    count++;
}
#define EXPECT(INFO,EXPR) if (total++,!(EXPR)) expect(INFO,#EXPR)

/* stack check..How can I do this better? */
ptrdiff_t check_grow(int k, int *p)
{
    if (p==0) p=&k;
    if (k==0) return &k-p;
    else return check_grow(k-1,p);
}
#define BITS_PER_INT (sizeof(int)*CHAR_BIT)

int bits_per_int=BITS_PER_INT;
int int_max=INT_MAX;
int int_min=INT_MIN;

/* for 21 - left to right */
int ltr_result=0;
unsigned ltr_fun(int k)
{
    ltr_result=ltr_result*10+k;
    return 1;
}

int main()
{
    printf("We like to think that:\n");
    /* characters */
    EXPECT("00 we have ASCII",('A'==65));
    EXPECT("01 A-Z is in a block",('Z'-'A')+1==26);
    EXPECT("02 big letters come before small letters",('A'<'a'));
    EXPECT("03 a char is 8 bits",CHAR_BIT==8);
    EXPECT("04 a char is signed",CHAR_MIN==SCHAR_MIN);

    /* integers */
    EXPECT("05 int has the size of pointers",sizeof(int)==sizeof(void*));
    /* not true for Windows-64 */
    EXPECT("05a long has at least the size of pointers",sizeof(long)>=sizeof(void*));

    EXPECT("06 integers are 2-complement and wrap around",(int_max+1)==(int_min));
    EXPECT("07 integers are 2-complement and *always* wrap around",(INT_MAX+1)==(INT_MIN));
    EXPECT("08 overshifting is okay",(1<<bits_per_int)==0);
    EXPECT("09 overshifting is *always* okay",(1<<BITS_PER_INT)==0);
    {
        int t;
        EXPECT("09a minus shifts backwards",(t=-1,(15<<t)==7));
    }
    /* pointers */
    /* Suggested by jalf */
    EXPECT("10 void* can store function pointers",sizeof(void*)>=sizeof(void(*)()));
    /* execution */
    EXPECT("11 Detecting how the stack grows is easy",check_grow(5,0)!=0);
    EXPECT("12 the stack grows downwards",check_grow(5,0)<0);

    {
        int t;
        /* suggested by jk */
        EXPECT("13 The smallest bits always come first",(t=0x1234,0x34==*(char*)&t));
    }
    {
        /* Suggested by S.Lott */
        int a[2]={0,0};
        int i=0;
        EXPECT("14 i++ is strictly left to right",(i=0,a[i++]=i,a[0]==1));
    }
    {
        struct {
            char c;
            int i;
        } char_int;
        EXPECT("15 structs are packed",sizeof(char_int)==(sizeof(char)+sizeof(int)));
    }
    {
        EXPECT("16 malloc()=NULL means out of memory",(malloc(0)!=NULL));
    }

    /* suggested by David Thornley */
    EXPECT("17 size_t is unsigned int",sizeof(size_t)==sizeof(unsigned int));
    /* this is true for C99, but not for C90. */
    EXPECT("18 a%b has the same sign as a",((-10%3)==-1) && ((10%-3)==1));

    /* suggested by nos */
    EXPECT("19-1 char<short",sizeof(char)<sizeof(short));
    EXPECT("19-2 short<int",sizeof(short)<sizeof(int));
    EXPECT("19-3 int<long",sizeof(int)<sizeof(long));
    EXPECT("20 ptrdiff_t and size_t have the same size",(sizeof(ptrdiff_t)==sizeof(size_t)));
#if 0
    {
        /* suggested by R. */
        /* this crashed on TC 3.0++, compact. */
        char buf[10];
        EXPECT("21 You can use snprintf to append a string",
               (snprintf(buf,10,"OK"),snprintf(buf,10,"%s!!",buf),strcmp(buf,"OK!!")==0));
    }
#endif

    EXPECT("21 Evaluation is left to right",
           (ltr_fun(1)*ltr_fun(2)*ltr_fun(3)*ltr_fun(4),ltr_result==1234));

    {
    #ifdef __STDC_IEC_559__
    int STDC_IEC_559_is_defined=1;
    #else 
    /* This either means, there is no FP support
     *or* the compiler is not C99 enough to define  __STDC_IEC_559__
     *or* the FP support is not IEEE compliant. */
    int STDC_IEC_559_is_defined=0;
    #endif
    EXPECT("22 floating point is always IEEE",STDC_IEC_559_is_defined);
    }

    printf("From what I can say with my puny test cases, you are %d%% mainstream\n",100-(100*count)/total);
    return 0;
}

ああ、そして私がこのコミュニティーwikiを最初から作成したのは、これを読んだときに人々が私のばらばらを編集したいと思ったからです。

更新ご入力いただきありがとうございます。私はあなたの答えからいくつかのケースを追加しました、そしてGregが提案するようにこれのためにgithubをセットアップできるかどうかを確認します。

更新:このためのgithubリポジトリを作成しました。ファイルは「gotcha.c」です。

パッチまたは新しいアイデアをここに回答してください。ここでそれらを議論または明確化できます。その後、それらをgotcha.cにマージします。


7
DOSの中型モデルを考えてみましょう。関数は複数のセグメントに格納できるため、関数ポインタは32ビット長です。ただし、データは単一のセグメントにのみ格納されるため、データポインターは16ビット長です。void *はデータポインターであるため、16ビット幅なので、関数ポインターを1つに収めることはできません。c-jump.com/CIS77/ASM/Directives/D77_0030_models.htmを参照してください。
ダビデは考える

6
おそらく、このコードをgithub.comか何かに投げ込めば、人々は簡単にパッチを提供できます。
グレッグヒューギル2010

1
ここで多くのことを助ける必要があります。stackoverflow.com/questions/367633/...
マーティンニューヨーク

4
POSIXでは、関数ポインターがvoid *と同じ表現を持ち、情報を失うことなく(キャストで)変換できる必要があります。これの理由の1つは、dlsym() void *返すことですが、データポインターと関数ポインターの両方を対象としています。したがって、これに依存することはそれほど悪くないかもしれません。
ジル

3
@tristopia:ポイント15がここにあります。多くの初心者は、データが連続的にパックされるのではなく、特定の境界に揃えられていることを知って驚くことが多いためです。メンバーの順序を変更してさまざまなオブジェクトサイズを取得すると、困惑します。また、パッキングは、現在の多くのマイクロコントローラーまたは組み込みデバイスのデフォルトモードです。AVR AtmegaおよびTurboC / MSDOS出力もパックされています。MSDOSはまだ産業用アプリケーションで使用されています。
Nordic Mainframe

回答:


91

を含む部分式の評価の順序

  • 関数呼び出しの引数と
  • 演算子のオペランド(例: +-=*/を除きます)、:
    • 二項論理演算子(&&および||)、
    • 三項条件演算子(?:)、および
    • カンマ演算子(,

ある未指定

例えば

  int Hello()
  {
       return printf("Hello"); /* printf() returns the number of 
                                  characters successfully printed by it
                               */
  }

  int World()
  {
       return printf("World !");
  }

  int main()
  {

      int a = Hello() + World(); //might print Hello World! or World! Hello
      /**             ^
                      | 
                Functions can be called in either order
      **/
      return 0;
  } 

1
関数のパラメーターについてはいつも知っていましたが、オペレーターの観点からは考えていませんでした... ...そして、そのようなコードを本番環境で書いているのを見たら、濡れた麺で叩きます。
riwalk 2010

3
@ビリー:しかし、演算子のプリミティブバージョンのみ。
Dennis Zickefoose 2010

1
@デニス:そうです。(これが、Effective / MoreEffective C ++のアイテムであり、それらをオーバーロードしないことを意味する理由です(あなたが書いている場合をboost::spirit
除き

1
@ダニエル:あなたが何を言おうとしているのかよくわかりません。演算子をオーバーロードしても大丈夫だと提案しているように思われます。クラスのユーザーだけが間違っている可能性があるためです。ストレートC ++で記述していなくても問題ありません。どちらもまったく意味がありません。
Dennis Zickefoose

2
@ user420536:動作は特定されていませんが、未定義ではありません。はい、例ではHello World!または世界!こんにちは。ただし、演​​算子のオペランドの評価順序が指定されていないため、これ+は指定されていません(コンパイラの作成者は動作を文書化する必要はありません)。それ自体、シーケンスポイントルールに違反していません。
Prasoon Saurav、2011

38

sdcc 29.7 / ucSim / Z80

We like to think that:
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..19-2 short<int
   but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
   but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
From what I can say with my puny test cases, you are Stop at 0x0013f3: (106) Invalid instruction 0x00dd

printfがクラッシュします。「O_O」


gcc 4.4@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 79% mainstream

gcc 4.4@x86_64-suse-linux(-O2)

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 82% mainstream

clang 2.7@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 72% mainstream

open64 4.2.3@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 75% mainstream

インテル11.1@x86_64-suse-linux

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..21a Function Arguments are evaluated right to left
but '(gobble_args(0,ltr_fun(1),ltr_fun(2),ltr_fun(3),ltr_fun(4)),ltr_result==4321)' is false.
ltr_result is 1234 in this case
..26 sizeof() does not evaluate its arguments
but '(i=10,sizeof(char[((i=20),10)]),i==10)' is false.
From what I can say with my puny test cases, you are 75% mainstream

Turbo C ++ / DOS / Small Memory

We like to think that:
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 81% mainstream

ターボC ++ / DOS /中型メモリ

We like to think that:
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..10 void* can store function pointers
but 'sizeof(void*)>=sizeof(void(*)())' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 78% mainstream

ターボC ++ / DOS /コンパクトメモリ

We like to think that:
..05 int has the size of pointers
but 'sizeof(int)==sizeof(void*)' is false.
..09a minus shifts backwards
but '(t=-1,(15<<t)==7)' is false.
..16 malloc()=NULL means out of memory
but '(malloc(0)!=NULL)' is false.
..19-2 short<int
but 'sizeof(short)<sizeof(int)' is false.
..20 ptrdiff_t and size_t have the same size
but '(sizeof(ptrdiff_t)==sizeof(size_t))' is false.
..22 floating point is always IEEE
but 'STDC_IEC_559_is_defined' is false.
..25 pointer arithmetic works outside arrays
but '(diff=&var.int2-&var.int1, &var.int1+diff==&var.int2)' is false.
..25a pointer arithmetic works outside arrays
but '(diff=&p1-&p2, &p2+diff==&p1)' is false.
From what I can say with my puny test cases, you are 75% mainstream

cl65 @ Commodore PET(副エミュレーター)

代替テキスト


これらは後で更新します。


Windows XP上のBorland C ++ Builder 6.0

..04 a char is signed
   but 'CHAR_MIN==SCHAR_MIN' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..16 malloc()=NULL means out of memory
   but '(malloc(0)!=NULL)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 71% mainstream

Visual Studio Express 2010 C ++ CLR、Windows 7 64ビット

(CLRコンパイラは純粋なCをサポートしていないため、C ++としてコンパイルする必要があります)

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream

MINGW64(gcc-4.5.2プレリリース)

- http://mingw-w64.sourceforge.net/

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..05a long has at least the size of pointers
   but 'sizeof(long)>=sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 67% mainstream

64は、WindowsはLLP64モデルを使用ビット:両方intlong32ビットの手段として定義され、そのいずれもポインタのための十分な長さです。


avr-gcc 4.3.2 / ATmega168(Arduino Diecimila)

失敗した仮定は次のとおりです。

..14 i++ is structly left to right
..16 malloc()=NULL means out of memory
..19-2 short<int
..21 Evaluation is left to right
..22 floating point is always IEEE

Atmega168には16ビットPCがありますが、コードとデータは別々のアドレス空間にあります。大きなAtmegaには22ビットPCがあります。


MacOSX 10.6上のgcc 4.2.1、-arch ppcでコンパイル

We like to think that:
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits come always first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream


32
そして、もう1つの仮定を識別しました。つまり、端末行に80文字を収めることができます。
Mike Seymour

3
sizeof(void*)>=sizeof(void(*)())==より関連性があります。私たちが気にしているのは「関数ポインターをvoidポインターに格納できるか」ということだけなので、テストする必要があるのvoid* a が少なくとも関数ポインターと同じ大きさかどうかです。
10

1
環境がPOSIXに準拠している場合は、問題ありません。opengroup.org/ onlinepubs / 009695399 / functions / dlsym.htmlをsizeof(void*)>=sizeof(void(*)())参照してください
Daniel Earwicker

26

ずっと前に、私は持っている教科書からCを教えていました

printf("sizeof(int)=%d\n", sizeof(int));

サンプルの質問として。この実装では、ではなくsizeofタイプの値が生成されるため、学生にとって失敗しました。16ビットで32であり、ビッグエンディアンでした。(プラットフォームは680x0ベースのMacintosh上のLightspeed Cでした。私はそれがずっと前だったと言った。)size_tintintsize_t


7
この種の最も一般的で見過ごされがちなエラーの1つを指摘するための+1。
R .. GitHub STOP

4
これは64ビットシステムでも発生し、size_tは64ビットで、intはほとんど常に短いです。size_tがunsigned long long存在するため、Win64は依然として変です。テスト17として追加
ノルディックメインフレーム

残念ながら、MicrosoftのCランタイムはサイズ付き整数のz修飾子をサポートしておらず、一部のプラットフォームでもサポートされていません。したがって、オブジェクトの印刷サイズをフォーマットまたはキャストするための安全でポータブルな方法はありません。size_tlong long
Phil Miller、

15

あなたは人々がする仮定++--仮定を含める必要があります。

a[i++]= i;

たとえば、は構文的には合法ですが、推論するには多すぎることに応じてさまざまな結果が生成されます。

++(または--)と変数が2回以上発生するステートメントは問題です。


そして、それもそのようなよくある質問です!
Matthieu M.

8

とても興味深い!

私が考えることができる他のことは、チェックするのに役立つかもしれません:

  • 関数ポインターとデータポインターは同じアドレス空間に存在しますか?(DOSスモールモードのようなハーバードアーキテクチャマシンの不具合。ただし、それをどのようにテストするかはわかりません。)

  • NULLデータポインターを受け取り、それを適切な整数型にキャストした場合、数値は0ですか?(一部の非常に古いマシンの破損--- http://c-faq.com/null/machexamp.htmlを参照してください。)関数ポインタを使用したDitto。また、値が異なる場合があります。

  • 対応するストレージオブジェクトの最後を超えてポインタをインクリメントし、その後再びインクリメントすると、適切な結果が得られますか?(私はこれが実際に壊れるマシンを知りませんが、C仕様では、(a)配列の内容または(b)要素のいずれかを指さないポインターについてさえ考えることができないと思います配列の直後または(c)NULL。http://c-faq.com/aryptr/non0based.htmlを参照してください。)

  • 異なるストレージオブジェクトへの2つのポインタを<と>で比較すると、一貫した結果が得られますか?(私はエキゾチックなセグメントベースのマシンでこれが壊れることを想像できます;仕様はそのような比較を禁止しているので、コンパイラーはポインターのオフセット部分のみを比較する権利があり、セグメント部分は比較されません。)

うーん。もう少し考えてみます。

編集:優れたC FAQへの明確なリンクをいくつか追加しました。


2
ちなみに、しばらく前に、CをLua、Javascript、Perl、LISPなどにコンパイルできるようにするClue(cluecc.sourceforge.net)という実験的なプロジェクトを行いました。ポインタを機能させるために、C標準の未定義の動作を容赦なく悪用しました。 。このテストを試すのは興味深いかもしれません。
デビッド・ギブン

1
IIRC Cでは、オブジェクトの終わりを超えてポインターを1だけインクリメントできますが、それ以上はインクリメントできません。ただし、オブジェクトの開始前の位置にデクリメントすることはできません。
R .. GitHub ICE HELPING ICEの停止

@R。C ++でも同じです。また、ポインタを整数として扱うだけではないCPUで、ポインタをインクリメントするとオーバーフローが発生する場合、さらにインクリメントを行うと壊れる可能性があります。
10

5

私は、「誤った」仮定の2つの非常に異なるクラスを区別する努力をする必要があると思います。適切な半分(右シフトと符号拡張、ASCII互換エンコーディング、メモリは線形、データと関数ポインターは互換性があるなど)は、プロトタイプなしのほとんどの Cコーダーあり、標準の一部として含まれていることさえあるCが今日設計されていて、レガシーIBMジャンクの祖父がいなかった場合。残りの半分(メモリのエイリアシングに関連するもの、入力メモリと出力メモリがオーバーラップするときのライブラリ関数の動作、ポインタが適合する、または使用できるという32ビットの仮定)場合、かなり妥当な仮定であり、呼び出し規則は可変および非可変で同じです関数、...)最近のコンパイラが実行したい最適化、または64ビットマシンやその他の新しいテクノロジへの移行と競合します。intmalloc


それは単なる「IBMジャンク」ではありません(IBMのものはジャンクであることに同意します)。今日、多くの組み込みシステムには同様の問題があります。
rmeador 2010

明確に言うとmalloc、プロトタイプなしで使用することは、64ビットをサポートする場合はを含めないことを意味し、デフォルト<stdlib.h>ではにmallocなりますint malloc(int)
ジョーイアダムス

技術的には<stdlib.h>、定義する別のヘッダーをインクルードし、正しいプロトタイプを使用してsize_t宣言する限り、自由にインクルードすることができmallocます。
R .. GitHub ICE HELPING ICEの停止

5

ここに楽しいものがあります:この関数の何が問題になっていますか?

float sum(unsigned int n, ...)
{
    float v = 0;
    va_list ap;
    va_start(ap, n);
    while (n--)
        v += va_arg(ap, float);
    va_end(ap);
    return v;
}

[回答(rot13):Inevnqvp nethzragf borl gur byq X&E cebzbgvba ehyrf、juvpu zrnaf lbh pnaabg hfr 'sybng'(be 'pune' be 'fubeg')va in_net!Naq gur pbzcvyre vf erdhverq abg gb gerng guvf nf n pbzcvyr-gvzr reebe。(TPP qbrf rzvg n jneavat、gubhtu。)]


ああ、それはいいことです。clang 2.7はこれを食べ、警告なしに完全なナンセンスを生成します。
Nordic Mainframe

va_argは、それがマクロであり、whileループが最初のステートメントのみを実行する場合に拡張されます。
マイスター

いいえ(それが起こった場合、実装のバグになります)。
zwol 2010

5
EXPECT("## pow() gives exact results for integer arguments", pow(2, 4) == 16);

もう1つは、のテキストモードに関するものですfopen。ほとんどのプログラマーは、テキストとバイナリーが同じである(Unix)か、テキストモードで\r文字が追加される(Windows)と想定しています。しかし、Cは固定幅のレコードを使用するシステムに移植されています。この場合fputc('\n', file)、テキストファイルでは、ファイルサイズがレコード長の倍数になるまでスペースなどを追加することになります。

そしてここに私の結果があります:

x86-64上のgcc(Ubuntu 4.4.3-4ubuntu5)4.4.3

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
From what I can say with my puny test cases, you are 78% mainstream

私は実際にpow(2, n)ビット操作と組み合わせたコードを見てきました。
dan04

4

それらの中には、仮定が成り立たない実装でプログラムがクラッシュする可能性があるため、Cの内部から簡単にテストできないものもあります。


「ポインター値の変数を使用して何を実行しても問題ありません。逆参照する場合にのみ、有効なポインター値を含める必要があります。」

void noop(void *p); /* A no-op function that the compiler doesn't know to optimize away */
int main () {
    char *p = malloc(1);
    free(p);
    noop(p); /* may crash in implementations that verify pointer accesses */
    noop(p - 42000); /* and if not the previous instruction, maybe this one */
}

unsigned charトラップ表現を持つことが許可されている整数型および浮動小数点型(を除く)と同じです。


「整数計算は折り返します。このため、このプログラムは大きな負の整数を出力します。」

#include <stdio.h>
int main () {
    printf("%d\n", INT_MAX+1); /* may crash due to signed integer overflow */
    return 0;
}

(C89のみ。)「の端から落ちても大丈夫ですmain。」

#include <stdio.h>
int main () {
    puts("Hello.");
} /* The status code is 7 on many implementations. */

2
具体例として:でコンパイルするgcc -ftrapv -Oと、出力のWe like to think that:後にAborted
caf

@caf: "このオプションは、加算、減算、乗算演算での符号付きオーバーフローのトラップを生成します。" 知ってよかった、ありがとう。
Gilles「SO-悪をやめる」

1
最後のものは、同様C ++(98、03および0X)で大丈夫です、と暗黙のうちに0を返します
jalf

ANSI以前のCではこれが許可され、C99でも許可されているため、これは厄介です。
ジョシュア

@ジョシュア:私の知る限りでは、ANSI以前のCとC89の間に値がない場合の違いはありませんmain。プログラムは正しいですが、未定義の終了ステータスを返します(C89§2.1.2.2)。多くの実装(gccや古いUNIXコンパイラなど)では、その時点で特定のレジスタにあったものをすべて取得します。プログラムは通常、終了ステータスをチェックするメイクファイルまたはその他の環境で使用されるまで機能します。
Gilles「SO-邪悪なこと

4

さて、まだ意図されていない古典的な移植性の仮定は

  • 整数型のサイズに関する仮定
  • エンディアン

4
「エンディアンがある」などの「エンディアン」:ミドルエンディアンのマシンがあり、標準ではshort値fedcab9876543210(16桁の2進数)を2バイトの0248aceとfdb97531として格納するなどの奇妙なことを許可しています。
Gilles「SO-邪悪なことをやめなさい」

はい、確かにエンディアンには、ビッグエンディアンとミドルエンディアンだけでなく、混合エンディアンとミドルエンディアンも含まれます。カスタムハードウェアにアクセスすると、どのバスでも好きなエンディアンを使用できます。
jk。

ミドルエンディアンはPDPエンディアンと呼ばれます。Gillesはさらに奇妙なことを述べていますが、それはTCP / IPの実装に頭痛の種となるでしょう。
ジョシュア

@ギレス:ミドルエンディアン...開発していないことをとても嬉しく思います。(しかし、私はミドルエンディアンネットワークプロジェクトを実行するように求められるでしょう、きっと)...
Paul Nathan

ARM FPEはミドルエンディアンのdoubleを使用し、<high quad> <low quad>ペアとして格納されていましたが、各quad内のビットの順序が間違っていました。(ありがたいことに、ARM VFPはこれ以上、これを行いません。)
ダビデは考える

4
  • 浮動小数点表現による離散化エラー。たとえば、標準の式を使用して二次方程式を解いたり、有限差分を使用して導関数を近似したり、標準の式を使用して分散を計算したりすると、類似値間の差の計算により精度が失われます。丸め誤差が累積するため、線形システムを解くガウスアルゴリズムは不適切です。そのため、QRまたはLU分解、コレスキー分解、SVDなどを使用します。浮動小数点数の加算は結合的ではありません。非正規、無限、およびNaN値があります。a + bab

  • 文字列:文字、コードポイント、コード単位の違い。さまざまなオペレーティングシステムでのUnicodeの実装方法。Unicodeエンコーディング。C ++では、任意のUnicodeファイル名のファイルを移植可能な方法で開くことはできません。

  • スレッド化しなくても競合状態:ファイルが存在するかどうかをテストすると、結果はいつでも無効になる可能性があります。

  • ERROR_SUCCESS = 0


4

整数サイズのチェックを含めます。ほとんどの人は、intはshortよりもcharよりも大きいと想定しています。ただし、これらはすべて間違っている可能性があります。sizeof(char) < sizeof(int); sizeof(short) < sizeof(int); sizeof(char) < sizeof(short)

このコードは失敗する可能性があります(非境界整列アクセスにクラッシュします)

unsigned char buf[64];

int i = 234;
int *p = &buf[1];
*p = i;
i = *p;

このコードはC ++で失敗しますか?IIRC、無関係な型の間でポインタをキャストすることは違法です。char*を除いて、任意の型にキャストできます(またはその逆ですか)。
rmeador 2010

1
あなたはちょうどint *p = (int*)&buf[1];C ++で行うことができました、人々はそれがうまくいくことを期待しています。
番号

@nos、ええ、それは失敗する可能性がありますが、失敗はクラッシュなので、彼のプログラムはそれをテストできません。:(
ジョシュア

1
sizeof(char) < sizeof(int)必要とされている。たとえば、fgetc()は、文字の値をintに変換された符号なしcharとして返すかEOF、負の値です。unsigned char埋め込みビットがない可能性があるため、これを行う唯一の方法は、intをcharより大きくすることです。また、C仕様(のほとんどのバージョン)では、-32767..32767の範囲の値をintに格納できる必要があります。
ジル

@illesはまだ、32ビット文字と32ビット整数を持つDSPがあります。
nos

3

組み込みデータ型に関するいくつかのこと:

  • charそしてsigned char、実際に2つの異なるタイプ(とは違っているintsigned int同じ符号付き整数型を参照します)。
  • 符号付き整数は、2の補数を使用する必要はありません。1の補数と符号+大きさも、負の数の有効な表現です。これにより、負の数を含むビット演算が実装定義されます。
  • 範囲外の整数を符号付き整数変数に割り当てる場合、動作は実装定義です。
  • C90では、またはを-3/5返すことができます。1つのオペランドが負の場合のゼロへの丸めは、C99以上およびC ++ 0x以上でのみ保証されます。0-1
  • 組み込み型の正確なサイズ保証はありません。標準のみカバーのような最小限の要件がint有する少なくとも 16ビットをlong有する少なくとも、32ビットをlong long有する少なくとも 64ビット。A floatは、少なくとも6つの上位10進数を正しく表すことができます。A doubleは、少なくとも上位10桁を正しく表すことができます。
  • IEEE 754は、浮動小数点数を表すために必須ではありません。

確かに、ほとんどのマシンには2の補数とIEEE 754浮動小数点数があります。


範囲外の整数割り当てを未定義の動作ではなく実装で定義することにはどのような価値があるのでしょうか。一部のプラットフォームでは、このような要件により、コンパイラーは追加のコードを生成する必要がありますint mult(int a,int b) { return (long)a*b;}(例:if intが32ビットで、レジスターlongが64の場合)。そのような要件がない場合、の「不可能な」値であっても、の最速の実装の「自然な」動作long l=mult(1000000,1000000);はに設定されます。l1000000000000int
スーパーキャット2014年

3

これはどう:

データポインターを有効な関数ポインターと同じにすることはできません。

これは、すべてのフラットモデル、MS-DOS TINY、LARGE、およびHUGEモデルではTRUE、MS-DOS SMALLモデルではfalse、MEDIUMモデルおよびCOMPACTモデルではほぼ常にfalse(ロードアドレスによって異なりますが、実際には古いDOSが必要です)それを真実にする)。

このためのテストを書くことはできません

さらに悪いことに、ptrdiff_tにキャストされたポインタが比較される場合があります。これはMS-DOS LARGEモデルには当てはまりません(LARGEとHUGEの唯一の違いは、HUGEがポインターを正規化するコンパイラーコードを追加することです)。

この爆弾がハードに配置されている環境では64Kを超えるバッファーが割り当てられないため、テストを記述できません。それを示すコードは、他のプラットフォームでクラッシュします。

この特定のテストは、現在消滅している1つのシステムに合格します(mallocの内部に依存することに注意してください)。

  char *ptr1 = malloc(16);
  char *ptr2 = malloc(16);
  if ((ptrdiff_t)ptr2 - 0x20000 == (ptrdiff_t)ptr1)
      printf("We like to think that unrelated pointers are equality comparable when cast to the appropriate integer, but they're not.");

3

編集:プログラムの最新バージョンに更新されました

Solaris-SPARC

32ビットのgcc 3.4.6

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 72% mainstream

64ビットのgcc 3.4.6

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09 overshifting is *always* okay
   but '(1<<BITS_PER_INT)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 68% mainstream

SUNStudio 11 32ビット

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
From what I can say with my puny test cases, you are 79% mainstream

SUNStudio 11 64ビット

We like to think that:
..05 int has the size of pointers
   but 'sizeof(int)==sizeof(void*)' is false.
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits always come first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is strictly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..17 size_t is unsigned int
   but 'sizeof(size_t)==sizeof(unsigned int)' is false.
From what I can say with my puny test cases, you are 75% mainstream

2

テキストモード(fopen("filename", "r"))を使用して、あらゆる種類のテキストファイルを読み取ることができます。

これ理論的には問題なく機能しますftell()が、コードでも使用していて、テキストファイルにUNIXスタイルの行末ftell()がある場合、Windows標準ライブラリの一部のバージョンでは、無効な値が返されることがよくあります。解決策は、代わりにバイナリモードを使用することです(fopen("filename", "rb"))。


1

AIX 5.3上のgcc 3.3.2(そうです、gccを更新する必要があります)

We like to think that:
..04 a char is signed
   but 'CHAR_MIN==SCHAR_MIN' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..13 The smallest bits come always first
   but '(t=0x1234,0x34==*(char*)&t)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..16 malloc()=NULL means out of memory
   but '(malloc(0)!=NULL)' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 71% mainstream

1

一部の人がC ++でstruct実行できることは、a structがCで実行できることに限定されていることです。実際、C ++では、a はclass、デフォルトですべてがパブリックであることを除いて、a に似ています。

C ++構造体:

struct Foo
{
  int number1_;  //this is public by default


//this is valid in C++:    
private: 
  void Testing1();
  int number2_;

protected:
  void Testing2();
};


1

32ビットx86上のVisual Studio Express 2010。

Z:\sandbox>cl testtoy.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

testtoy.c
testtoy.c(54) : warning C4293: '<<' : shift count negative or too big, undefined
 behavior
Microsoft (R) Incremental Linker Version 10.00.30319.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:testtoy.exe
testtoy.obj

Z:\sandbox>testtoy.exe
We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..09a minus shifts backwards
   but '(t=-1,(15<<t)==7)' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
..22 floating point is always IEEE
   but 'STDC_IEC_559_is_defined' is false.
From what I can say with my puny test cases, you are 78% mainstream

1

Codepad.orgC++: g++ 4.1.2 flags: -O -std=c++98 -pedantic-errors -Wfatal-errors -Werror -Wall -Wextra -Wno-missing-field-initializers -Wwrite-strings -Wno-deprecated -Wno-unused -Wno-non-virtual-dtor -Wno-variadic-macros -fmessage-length=0 -ftemplate-depth-128 -fno-merge-constants -fno-nonansi-builtins -fno-gnu-keywords -fno-elide-constructors -fstrict-aliasing -fstack-protector-all -Winvalid-pch)経由。

コードパッドにはないことに注意してくださいstddef.h。エラーとして警告を使用するコードパッドのため、テスト9を削除しました。count何らかの理由で既に定義されているため、変数の名前も変更しました。

We like to think that:
..08 overshifting is okay
   but '(1<<bits_per_int)==0' is false.
..14 i++ is structly left to right
   but '(i=0,a[i++]=i,a[0]==1)' is false.
..15 structs are packed
   but 'sizeof(char_int)==(sizeof(char)+sizeof(int))' is false.
..19-3 int<long
   but 'sizeof(int)<sizeof(long)' is false.
From what I can say with my puny test cases, you are 84% mainstream

1

過剰な量の右シフトはどうですか?それは標準で許可されていますか、それともテストする価値がありますか?

標準Cは次のプログラムの動作を指定していますか?

void print_string(char * st)
{
  char ch;
  while((ch = * st ++)!= 0)
    putch(ch); / *これが定義されていると仮定します* /
}
int main(void)
{
  print_string( "Hello");
  0を返します。
}

私が使用する少なくとも1つのコンパイラでは、print_stringへの引数が「char const *」でない限り、そのコードは失敗します。規格はそのような制限を許可していますか?

一部のシステムでは、アライメントされていない「int」へのポインタを生成できますが、他のシステムでは生成できません。テストする価値があるかもしれません。


C89§3.3.7:「右のオペランドの値が負であるか、プロモートされた左のオペランドのビット単位の幅以上である場合、動作は未定義です。」(<<およびの両方に適用されます>>)。C99は、§6.5.7-3と同じ言語です。
Gilles「SO-邪悪なことをやめなさい」

putch(なぜ標準を使用しなかったのですputcharか?)とは別に、プログラムで未定義の動作を確認することはできません。C89§3.1.4は、「文字列リテラルに[…]タイプ 'charの配列'がある」(注:no const)こと、および「プログラムが文字列リテラル[…]を変更しようとした場合の動作は未定義」と規定しています。それはどのコンパイラですか、そしてどのようにこのプログラムを翻訳しますか?
Gilles「SO-邪悪なことをやめなさい」2010

2
C ++では、文字定数はchar []ではなく、const char []です。ただし、以前は型システムに特定の穴があり、char *が予期されていて型エラーが発生しないコンテキストで文字列定数を使用できるようにしていました。これにより、print_string( "foo")は機能するが、print_string( "foo" +0)は機能しない状況が発生しました。これは、特にCファイルがデフォルトでC ++コンパイラーを使用してコンパイルされる環境では、非常に混乱しました。新しいコンパイラーではこの穴は取り除かれましたが、まだ古いコンパイラーがたくさんあります。AFAIK C99はまだ文字列定数をchar []と定義しています。
デビッドギヴン

1
Microchip PICシリーズのコントローラー用のHiTechコンパイラーでは、ストレージ修飾子のないポインターはRAMのみを指すことができます。constで修飾されたポインタは、RAMまたはROMのいずれかを指すことができます。constで修飾されていないポインタは、コードで直接逆参照されます。constで修飾されたポインタは、ライブラリルーチンを介して逆参照されます。PICの特定のタイプに応じて、非const修飾ポインターは1バイトまたは2バイトです。constで修飾されたものは2または3です。ROMはRAMよりもはるかに豊富であるため、ROMに定数があることは一般的に良いことです。
スーパーキャット

@David Given:私の以前のコメントにも注意してください。ハードウェアストレージクラスを示すために、 "const"以外の修飾子を使用するコンパイラを好みます。HiTechコンパイラには、ストレージクラスの割り当てにかなり厄介な癖があります(たとえば、「コンポーネントサイズ」がバイトであるデータアイテム、または256バイトを超えるデータアイテムは、「大きな」セグメントに入ります。他のデータアイテムは「 BSS」彼らは定義されているモジュールのセグメントは、すべての『モジュール内のBSS』の項目には、256バイト以内に収まらなければなりません少し短い256バイトのある配列を本当の迷惑することができます。。
supercat

0

参考までに、CのスキルをJavaに変換する必要がある人のために、ここにいくつかの落とし穴があります。

EXPECT("03 a char is 8 bits",CHAR_BIT==8);
EXPECT("04 a char is signed",CHAR_MIN==SCHAR_MIN);

Javaでは、charは16ビットであり、署名されています。バイトは8ビットで、符号付きです。

/* not true for Windows-64 */
EXPECT("05a long has at least the size of pointers",sizeof(long)>=sizeof(void*));

longは常に64ビットです。参照は32ビットまたは64ビットにすることができます(32 GBを超えるアプリがある場合)64ビットJVMは通常32ビット参照を使用します。

EXPECT("08 overshifting is okay",(1<<bits_per_int)==0);
EXPECT("09 overshifting is *always* okay",(1<<BITS_PER_INT)==0);

シフトはマスクされるため、i << 64 == i == i << -64、i << 63 == i << -1

EXPECT("13 The smallest bits always come first",(t=0x1234,0x34==*(char*)&t));

ByteOrder.nativeOrder()はBIG_ENDIANまたはLITTLE_ENDIANにできます

EXPECT("14 i++ is strictly left to right",(i=0,a[i++]=i,a[0]==1));

i = i++ 決して変わらない i

/* suggested by David Thornley */
EXPECT("17 size_t is unsigned int",sizeof(size_t)==sizeof(unsigned int));

コレクションと配列のサイズは、JVMが32ビットか64ビットかに関係なく、常に32ビットです。

EXPECT("19-1 char<short",sizeof(char)<sizeof(short));
EXPECT("19-2 short<int",sizeof(short)<sizeof(int));
EXPECT("19-3 int<long",sizeof(int)<sizeof(long));

charは16ビット、shortは16ビット、intは32ビット、longは64ビットです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.