c语言 - 具有异常内存字大小的"char*"(高德纳的MIX架构)



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

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

我能想到的方法:

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

因此,这似乎留下了使用31位字符的第一个(浪费的)选项,所有对象的大小都是字符的倍数——我这样读对吗?

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

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

char hi[4];
hi[0] = 'hell';
hi[1] = 'o, w';
hi[2] = 'orld';
hi[3] = '';
printf("%s", hi);
// Whoops, we forgot the exclamation mark
putchar('!n');

这个实现看起来很奇怪,但根据维基百科的说法,它被用于有史以来第一个"你好世界"程序。我看了一下标准,没有发现任何阻碍,即使是在C11中。特别是§6.4.4.4允许以特定于实现的方式对文字字符和字符串进行编码。

编辑:

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

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

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

native_type a, b;
a.as_int = 0xC11BABE;
b.as_bytes.byte4 = a.as_bytes.byte4; // Whoops

将产生未定义的行为:有关详细信息,请参阅此处。

最实用的方法可能是使int为30位,并使char为10或15。对char使用10位将允许ASCII文本被更紧密地打包,但由于需要除以3,将增加索引到char数组的成本。使用10字节或15字节的char,Unicode文本的存储可能相当高效。对于15字节的char,大约30720个码点将占用15个比特,其余的将占用30个比特。对于10字节的char,128个代码点将占用10位,65408将占用20位,其余部分将占用30位。

为了减少除以3的成本,使每个char*包含两个单词可能是有帮助的;一个将识别包含该字符的单词,另一个将以字符为单位识别该单词开头的偏移量。向已知被规范化的指针添加常量偏移量可以使用以下代码:

p += 5; // Becomes...
if (p.offset) { p.offset=2; p.base+=1; }
else { p.offset--; p.base+=2; }

不太好,但这将避免任何"分裂"步骤的需要。

最新更新