代码之家  ›  专栏  ›  技术社区  ›  Adil Akhter

什么是一个教育工具来证明人们在C/C++中做出的毫无根据的假设?

  •  118
  • Adil Akhter  · 技术社区  · 5 年前

    我想准备一个小的教育工具,这样可以帮助初学者(和中级)程序员认识和挑战他们在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;
    }
    

    哦,我从一开始就做了这个社区维基,因为我觉得人们在读这个的时候想编辑我的博客。

    更新 谢谢你的意见。我已经从您的答案中添加了一些案例,并将查看我是否可以像Greg建议的那样为此设置GitHub。

    更新 : 我已经为此创建了一个github repo,文件是“gotcha.c”:

    请在这里回答补丁或新想法,以便在这里讨论或澄清。我会把它们合并到gotcha.c中。

    23 回复  |  直到 13 年前
        1
  •  90
  •   Prasoon Saurav    14 年前

    子表达式的计算顺序,包括

    • 函数调用的参数和
    • 运算符的操作数(例如, + , - , = , * , / ,以下情况除外:
      • 二元逻辑运算符( && || )
      • 三元条件运算符( ?: )
      • 逗号运算符( , )

    未指定

    例如

      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;
      } 
    
        2
  •  37
  •   Adil Akhter    14 年前

    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崩溃。“奥欧


    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/小内存

    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/媒体存储器

    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
    

    Turbo 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 http://i34.tinypic.com/2hh0zmc.png


    稍后我将更新这些:


    WindowsXP上的Borland C++ Builder 6

    ..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位

    (必须编译为C++,因为CLR编译器不支持纯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模型:两者都使用 int long 定义为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!.


    GCC 4.2.1关于MacOSX 10.6,用-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
    

        3
  •  24
  •   David Thornley    14 年前

    很久以前,我在一本教科书上教C

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

    作为一个示例问题。对一个学生来说失败了,因为 sizeof 生成类型的值 size_t 不是 int , int 在这个实现上是16位 小精灵 当时32岁,是大尾音。(平台是基于680x0的Macintosh的Lightspeed C。我说那是很久以前的事了。)

        4
  •  15
  •   S.Lott    14 年前

    你需要包括 ++ -- 人们的假设。

    a[i++]= i;
    

    例如,在句法上是合法的,但根据太多的事情而产生不同的结果。

    任何有 ++ (或) —— )一个多次出现的变量是一个问题。

        5
  •  8
  •   David Given    14 年前

    非常有趣!

    我能想到的其他事情可能有助于检查:

    • 函数指针和数据指针是否存在于同一地址空间中?(像DOS小型模式这样的哈佛建筑机器出现故障。但不知道你会如何测试它。)

    • 如果获取一个空数据指针并将其强制转换为适当的整数类型,它是否具有数值0?(打破了一些真正古老的机器---见 http://c-faq.com/null/machexamp.html .)同上,带有函数指针。而且,它们可能是不同的值。

    • 增加一个指针,使其超过其相应存储对象的末尾,然后再返回,是否会导致合理的结果?(我不知道有什么机器会坏,但我相信C规格不允许你 认为 关于不指向(a)数组内容或(b)数组后面的元素或(c)空的指针。见 http://c-faq.com/aryptr/non0based.html )

    • 使用<和>比较指向不同存储对象的两个指针是否会产生一致的结果?(我可以想象在基于段的机器上发生了这种中断;规范禁止这种比较,因此编译器有权只比较指针的偏移部分,而不比较段部分。)

    嗯。我会再想一想的。

    编辑: 为优秀的C FAQ添加了一些清晰的链接。

        6
  •  5
  •   R..    14 年前

    我认为你应该努力区分两种截然不同的“错误”假设。好的一半(右移位和符号扩展、与ASCII兼容的编码、内存是线性的、数据和函数指针是兼容的等)是相当合理的假设 如果C是在今天被设计的,如果我们没有IBM旧货的继承权,甚至可能被包括在标准中。另一半(与内存别名有关的事情,当输入和输出内存重叠时库函数的行为,像指针这样的32位假设适合 int 或者你可以用 malloc 如果没有原型,那么变量和非变量函数的调用约定是相同的,…)或者与现代编译器想要执行的优化冲突,或者与迁移到64位计算机或其他新技术冲突。

        7
  •  4
  •   jk.    14 年前

    好吧,经典的可移植性假设还没有意味着

    • 关于积分类型大小的假设
    • 终结性
        8
  •  4
  •   idrosid    14 年前
    • 浮点表示导致的离散化错误。例如,如果使用标准公式来求解二次方程,或使用有限差来近似导数,或使用标准公式来计算方差,则由于计算相似数字之间的差异,精度将丢失。由于舍入误差的累积,使得求解线性系统的高斯算法很差,因此采用QR或LU分解、Cholesky分解、SVD等方法,浮点数的加法是不相关的。有非正规值、无限值和NaN值。 + 艾斯 阿西 .

    • 字符串:字符、代码点和代码单位之间的差异。Unicode是如何在各种操作系统上实现的;Unicode编码。用一个任意的Unicode文件名打开一个文件是不可能的。

    • 竞态条件,即使没有线程:如果测试文件是否存在,结果可能随时变为无效。

    • ERROR_SUCCESS = 0

        9
  •  4
  •   zwol    14 年前

    这是一个有趣的例子:这个函数有什么问题?

    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!Naq Gur Pbzcvyre VF Erdhverq ABG GB Gerng Guvf NF N Pbzcvyr Gvzr Reebe公司。(TPP QBRF RZVG N JNEAVT,Gubhtu.)]

        10
  •  4
  •   dan04    14 年前
    EXPECT("## pow() gives exact results for integer arguments", pow(2, 4) == 16);
    

    另一个是关于文本模式 fopen . 大多数程序员假定文本和二进制文件是相同的(unix),或者文本模式添加了 \r 字符(窗口)。但是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
    
        11
  •  3
  •   Gilles    14 年前

    其中一些很难在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. */
    
        12
  •  3
  •   nos    14 年前

    包括对整数大小的检查。 大多数人认为int是 大于空头大于空头 烧焦。然而,这些可能都是 假: 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;
    
        13
  •  3
  •   sellibitze    14 年前

    关于内置数据类型的几个方面:

    • char signed char 实际上是两种不同的类型(不同于 int signed int 指的是相同的有符号整数类型)。
    • 有符号整数不需要使用二的补码。一个数的补码和符号+数量级也是负数的有效表示。这使得位运算涉及负数。 定义的实现 .
    • 如果将超出范围的整数赋给有符号整数变量,则行为为 定义的实现 .
    • 在C90中, -3/5 可能返回 0 -1 . 在一个操作数为负的情况下,舍入为零仅在C99向上和C++0X向上保证。
    • 内置类型没有确切的大小保证。本标准仅涵盖最低要求,如 int 至少 16位,A long 至少 32位,A long long 至少 64位。一 float 至少能正确代表6位最有效的十进制数字。一 double 至少能正确代表10位最有效的十进制数字。
    • IEEE 754不是表示浮点数的强制要求。

    诚然,在 机器我们有两个补码和IEEE754浮点数。

        14
  •  3
  •   Thomas    14 年前

    编辑:更新到程序的最新版本

    Solaris SPARC

    GCC 3.4.6,32位

    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
    

    GCC 3.4.6,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.
    ..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
    
        15
  •  2
  •   Joshua    14 年前

    这个怎么样:

    任何数据指针都不能与有效的函数指针相同。

    对于所有平面模型、MS-DOS小型、大型和大型模型,这是正确的;对于MS-DOS小型模型,这是错误的;对于中型和小型模型,这几乎总是错误的(取决于加载地址,您需要一个真正老的DOS来实现这一点)。

    我不能为这个写测试

    更糟的是:可以比较指向ptridff的指针。这对MS-DOS大型模型来说是不正确的(大型和大型之间的唯一区别是大量添加编译器代码来规范化指针)。

    我不能写一个测试,因为在这样的环境中,这个炸弹很难分配一个大于64K的缓冲区,所以演示它将在其他平台上崩溃的代码。

    此特定测试将通过一个现已失效的系统(注意,这取决于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.");
    
        16
  •  2
  •   Chinmay Kanchi    14 年前

    可以使用文本模式( fopen("filename", "r") )读取任何类型的文本文件。

    当这个 应该 理论上讲,如果你也使用 ftell() 在您的代码中,您的文本文件有Unix样式的行尾,在某些版本的Windows标准库中, ftell()。 通常返回无效值。解决方案是改用二进制模式( fopen("filename", "rb") )

        17
  •  1
  •   chauncey    14 年前

    在AIX5.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
    
        18
  •  1
  •   Alerty    14 年前

    一个假设,有些可能在C++中是这样的 struct 局限于它在C中能做什么。事实上,在C++中, 结构 就像一个 class 只是它默认所有的事情都是公开的。

    C++结构:

    struct Foo
    {
      int number1_;  //this is public by default
    
    
    //this is valid in C++:    
    private: 
      void Testing1();
      int number2_;
    
    protected:
      void Testing2();
    };
    
        19
  •  1
  •   arsenm    14 年前

    不同系统上的标准数学函数不能给出相同的结果。

        20
  •  1
  •   Paul Nathan    14 年前

    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
    
        21
  •  1
  •   Brian    14 年前

    通孔 Codepad.org ( C++: 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
    
        22
  •  1
  •   supercat    14 年前

    以过多的数量进行正确的转换——这是标准允许的,还是值得测试的?

    标准C是否规定了以下程序的行为:

    void print_string(char *st)
    {
      char ch;
      while((ch = *st++) != 0)
        putch(ch);  /* Assume this is defined */
    }
    int main(void)
    {
      print_string("Hello");
      return 0;
    }
    

    在我使用的至少一个编译器上,除非要打印字符串的参数是“char”,否则该代码将失败。 康斯特 *标准是否允许这样的限制?

    有些系统允许一个生成指向未对齐的“int”的指针,而其他系统则不允许。可能值得测试。

        23
  •  0
  •   Peter Lawrey    13 年前

    对于那些必须把C技能翻译成Java的人来说,这里有几个窍门。

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

    在爪哇,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()可以是大的或小的

    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位。