什么属于教育工具,以展示人们在C/C++中做出的无根据的假设?

Nor*_*ame 120 c c++ portability cross-platform

我想为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;
}
Run Code Online (Sandbox Code Playgroud)

哦,我从一开始就制作了这个社区维基,因为我认为人们想要在阅读时编辑我的诽谤.

更新感谢您的意见.我已经从你的答案中添加了一些案例,并会看看我是否可以像Greg建议的那样设置github.

更新:我为此创建了一个github仓库,文件是"gotcha.c":

请在这里回答补丁或新想法,这里可以讨论或澄清它们.我将它们合并到gotcha.c然后.

Pra*_*rav 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;
  } 
Run Code Online (Sandbox Code Playgroud)

  • @Billy:但仅适用于运营商的原始版本. (3认同)
  • @ user420536:行为未指定但未定义.是的,这个例子可以打印Hello World!还是世界!你好,但这只是未指定,因为`+`运算符的操作数的评估顺序是未指定的(编译器编写者不需要记录行为).它不违反任何[序列点](http://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points)规则. (2认同)

Nor*_*ame 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

intel 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Turbo C++/DOS/Compact Memory

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
Run Code Online (Sandbox Code Playgroud)

cl65 @ Commodore PET(副仿真器)

alt text http://i34.tinypic.com/2hh0zmc.png


我稍后会更新这些:


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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Atmega168具有16位PC,但代码和数据位于不同的地址空间中.较大的Atmegas有22位PC!


Mac OSX 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
Run Code Online (Sandbox Code Playgroud)

  • 而且你已经确定了另一个假设:你可以在终端线上放置80个字符. (31认同)
  • `sizeof(void*)> = sizeof(void(*)())`比==更相关.我们所关心的只是"我们可以将函数指针存储在void指针中",所以你需要测试的假设是`void*`是*至少*是否与函数指针一样大. (3认同)

Dav*_*ley 26

很久以前,我从一本教科书中教授C语言

printf("sizeof(int)=%d\n", sizeof(int));
Run Code Online (Sandbox Code Playgroud)

作为一个示例问题.它失败的学生,因为sizeof类型的产量值size_t,不是int,int在这个实现为16位,size_t为32,这是大端.(该平台是基于680x0的Macintoshes上的Lightspeed C.我说很久以前了.)

  • +1表示这种最常见且常被忽视的错误之一. (7认同)
  • 这也发生在64位系统上,其中size_t为64位且整数几乎总是更短.Win64仍然比较怪异,因为size_t在那里是一个`unsigned long long`.添加为测试17. (4认同)

S.L*_*ott 15

您需要包括++--假设人做.

a[i++]= i;
Run Code Online (Sandbox Code Playgroud)

例如,在语法上是合法的,但根据太多的理由产生不同的结果.

任何具有++(或--)和多次出现的变量的语句都是一个问题.


Dav*_*ven 8

很有意思!

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

  • 函数指针和数据指针存在于同一地址空间?(在DOS小模式下哈佛架构机器中断.虽然不知道你是如何测试它的.)

  • 如果您使用NULL数据指针并将其强制转换为适当的整数类型,它是否具有数值0?(打破一些非常古老的机器---请参阅http://c-faq.com/null/machexamp.html.)同上功能指针.而且,它们可能是不同的值.

  • 将指针递增超过其相应存储对象的末尾,然后再返回,会产生明显的结果吗?(我不知道这实际上打破上的任何机器,但我相信C时的参数不允许你甚至认为有关不点指针或者(a)的阵列或(b)该元素的内容紧接在数组之后或(c)NULL.请参阅http://c-faq.com/aryptr/non0based.html.)

  • 比较两个指向不同存储对象的指针与<和>产生一致的结果?(我可以想像,在异国情调的片段式的机器这一创;规范禁止这种比较,所以编译器将有权进行比较的唯一指针,而不是段部分的冲销部分).

嗯.我会试着想一些.

编辑:添加了一些优秀的C FAQ的澄清链接.

  • 顺便说一下,我做了一个名为Clue的实验项目(http://cluecc.sourceforge.net),它允许你将C编译成Lua,Javascript,Perl,LISP等.它无情地利用了C标准中未定义的行为.使指针工作.尝试这个测试可能会很有趣. (2认同)

R..*_*R.. 5

我认为你应该努力区分两种截然不同的"错误"假设.良好的一半(右移和符号扩展,ASCII兼容编码,内存是线性的,数据和函数指针兼容等)对于大多数 C编码器来说是非常合理的假设,甚至可能作为标准的一部分包含在内如果C今天正在设计,如果我们没有遗留下来的旧版IBM垃圾邮件.另一半(与内存别名相关的事情,输入和输出内存重叠时库函数的行为,像指针适合的32位假设int或者你可以使用malloc 没有原型,调用约定对于可变和非可变函数是相同的,...)要么与现代编译器想要执行的优化冲突,要么与迁移到64位机器或其他新技术冲突.


zwo*_*wol 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;
}
Run Code Online (Sandbox Code Playgroud)

[答案(rot13):Inevnqvp nethzragf borl gur byq X&E cebzbgvba ehyrf,juvpu zrnaf lbh pnaabg hfr'sybng'('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。)]


dan*_*n04 5

EXPECT("## pow() gives exact results for integer arguments", pow(2, 4) == 16);
Run Code Online (Sandbox Code Playgroud)

另一个是关于中的文本模式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
Run Code Online (Sandbox Code Playgroud)