web-dev-qa-db-ja.com

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

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

例:

  • 「整数は回り込む」
  • 「誰もが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を最初から作成したのは、人々がこれを読んだときに私のばらばらを編集したいと思っているからです。

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

[〜#〜] update [〜#〜]:このためのgithubリポジトリを作成しました。ファイルは "gotcha.c"です:

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

121

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

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

is nspecified

例えば

  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;
  } 
91
Prasoon Saurav

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 [email protected]_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 [email protected]_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 [email protected]_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 [email protected]_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

インテル[email protected]_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

Turbo C++/DOS/Medium Memory

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(副エミュレータ)

alt text


後で更新します:


Borland C++ Builder 6.0 on Windows XP

..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モデルを使用します。intlongはどちらも32ビットとして定義されています。つまり、どちらもポインターに対して十分な長さではありません。


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があります。


-Arch ppcでコンパイルされたMacOSX 10.6上のgcc 4.2.1

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

38

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

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

サンプルの質問として。 sizeofintではなくsize_t型の値を生成するため、この実装ではintは16ビットであり、size_tは32、それはビッグエンディアンでした。 (プラットフォームは680x0ベースのMacintosh上のLightspeed Cでした。私はそれがずっと前だったと言った。)

26
David Thornley

人々が行う++および--の仮定を含める必要があります。

a[i++]= i;

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

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

15
S.Lott

とても興味深い!

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

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

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

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

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

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

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

8
David Given

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

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

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

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

gcc(Ubuntu 4.4.3-4ubuntu5)4.4.3 on x86-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.
..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
_
5
dan04

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

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。)]

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

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

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

  • ERROR_SUCCESS = 0

4
Philipp

整数サイズのチェックを含めます。ほとんどの人は、intはshortよりもcharよりも大きいと想定しています。ただし、これらはすべてfalseである可能性があります: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;
4
nos

前提条件が満たされない実装ではプログラムがクラッシュする可能性が高いため、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. */

まあまだ言及されていない古典的な移植性の仮定は

  • エンディアン
4
jk.

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

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

確かに、mostマシンでは、2の補数とIEEE 754フロートがあります。

3
sellibitze

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

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
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
Joshua

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

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

2
Chinmay Kanchi

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

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

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

私が使用している少なくとも1つのコンパイラでは、print_stringへの引数が "char const * "。このような制限は規格で許可されていますか?

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

1
supercat

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
chauncey

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

C++構造体:

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


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

protected:
  void Testing2();
};
_
1
Alerty

異なるシステムの標準的な数学関数は、同じ結果を与えません。

1
arsenm

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
Paul Nathan

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
Brian

参考までに、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ビットです。

0
Peter Lawrey