"char*"具有不寻常的内存字大小(Knuth的MIX架构)

Sof*_*yro 14 c knuth bit memory-address language-lawyer

最初的MIX架构具有6位字节,存储器被寻址为31位字(5个字节和一个符号位).作为一个思考练习,我想知道C语言如何在这种环境中发挥作用,给出:

  • char至少有8位(C99规范附件E)
  • C99规范6.3.2.3节("指针")第8段说"当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节.结果连续增加,向上到对象的大小,产生指向对象剩余字节的指针." 我对这个要求的解释是它支持"memcpy(&dst_obj,&src_obj,sizeof(src_obj))".

我能想到的方法:

  1. 使char为31位,因此通过"char*"间接是简单的内存访问.但这会使字符串浪费(并且意味着它不符合POSIX标准,因为它显然需要8位字符)
  2. 将3个8位字符打包成一个字,7个忽略位:"char*"可能由字地址和字符索引组成.然而,这似乎违反了6.3.2.3,即memcpy()必然会跳过忽略的位(这对于真实对象类型可能有意义)
  3. 将字符完全打包成单词,例如第四个8位字符在字0中有7位,在字1中有一位.但是这似乎要求所有对象都是8位字符大小,例如"uint31_t"不能声明匹配单词长度,因为这又有memcpy()问题.

所以这似乎留下了使用31位字符的第一个(浪费)选项,所有对象的大小都是char的倍数 - 我是否正确地阅读它?

Alb*_*o M 5

我同意 MIX 架构上的 C 实现起来可能很痛苦,尽管我自己不是语言律师,但在我看来,你指出你的方法 1. 是唯一符合标准的方法是正确的。

\n\n

无论如何,字符串的空间浪费是最不重要的问题:您可以通过诉诸比 C 本身更早的解决方案来规避它:使每个char代表多个字母。对于 MIX 架构,您可以设计一个 7 位编码并将 4 个字母打包到每个字符中:

\n\n
char hi[4];\nhi[0] = \'hell\';\nhi[1] = \'o, w\';\nhi[2] = \'orld\';\nhi[3] = \'\\0\';\n\nprintf("%s", hi);\n\n// Whoops, we forgot the exclamation mark\nputchar(\'!\\n\');\n
Run Code Online (Sandbox Code Playgroud)\n\n

这个实现看起来很奇怪,但根据维基百科,它被用在第一个“Hello world”程序中。我查看了标准,发现没有什么可以阻止它,即使在 C11 中也是如此。特别是 \xc2\xa7 6.4.4.4 允许以特定于实现的方式对文字字符和字符串进行编码。

\n\n

编辑:

\n\n

这无助于解决其他困难,主要的困难是您无法使用机器的大部分可能指令,因为您无法使用本机 C 类型来寻址单个字节。但是,您可以通过以下方式使用位域:

\n\n
typedef struct _bytes {\n    unsigned int sign  : 1;\n    unsigned int byte1 : 6; // EDIT: bitfields must be \n    unsigned int byte2 : 6; // declared as ints in standard C\n    unsigned int byte3 : 6;\n    unsigned int byte4 : 6;\n    unsigned int byte5 : 6;\n} bytes;\n\ntypedef union _native_type {\n    char as_word;\n    int as_int; // int = char; useful for standard library functions, etc.\n    bytes as_bytes;\n} native_type;\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,在 C++ 中,由于严格别名规则中的子句,您必须小心地始终访问char介于 1int和 1之间的成员bytes之间的成员,因为以下代码片段:

\n\n
native_type a, b;\na.as_int = 0xC11BABE;\nb.as_bytes.byte4 = a.as_bytes.byte4; // Whoops\n
Run Code Online (Sandbox Code Playgroud)\n\n

会产生未定义的行为:请参阅此处了解详细信息。

\n