是否需要保留填充位?

时间:2015-07-18 20:01:40

标签: c padding language-lawyer msp430

MSP430X架构是16位MSP430架构到20位地址空间的扩展。这是通过将处理器的寄存器扩展到20位,将最小可寻址单元保持在一个八位位组(CHAR_BIT等于8)来完成的。

在这个架构上,人们可以想到一种C编程语言的实现,它为int提供20位整数类型,使用8位char,一个16位short和一个模拟的32位long。由于20不是CHAR_BIT的倍数,因此在存储类型int的变量时需要一些填充位。例如,可以在四个字节中存储int,将一个字节和另一个字节的四个位作为填充。

在阅读了关于整数类型填充位的标准说明后,我不确定它们应该如何表现。由于在这种情况下填充仅用于存储,因此除了类型打孔之外,它们的值既不能设置也不能被观察。即使这样,复制这种20位类型的对象也不会复制任何填充位。 ISO 9899:2011是否允许这样的填充位?

2 个答案:

答案 0 :(得分:3)

C标准不要求通过赋值复制填充位。分配是根据值而非表示来指定的。

N1570 6.2.6.2p5说:

  

未指定任何填充位的值。

这是一个无条件的声明,暗示它们在所有情况下都未指定,即使在从设置了一些填充位的对象进行赋值之后也是如此。

就其本身而言,该陈述可能被认为足够模糊,以至于它没有确定填充位不一定被复制。

填充位对整数对象的表示没有贡献。引用句子的脚注说:

  

填充位的所有其他组合是替代对象   由值位指定的值的表示。

(“其他”是指陷阱表示。)

描述简单赋值的

6.5.16.1p2说:

  

简单作业 = )中,右操作数的值被转换   到赋值表达式的类型并替换存储的值   在左操作数指定的对象中。

说明是根据而非表示;没有任何暗示RHS的表示必须保留在LHS对象中。当然,赋值中的RHS可以是任意表达式,而不仅仅是对象引用。即使它只是一个对象的名称,它也会经历左值转换,如6.3.2.1p2中所述;此转换仅指对象的值,而不是其表示。

(在其他地方,标准表示参数传递,函数参数传递以及从函数返回值的行为类似于简单赋值。)

答案 1 :(得分:1)

通常,标准会在sizeof类型上设置一些约束。基本约束是它必须是char whith sizeof(char)定义为1的倍数。

对于类型中的填充位,请参阅6.2.6.1,其中表示主要是实现定义6.2.6.2p5表示填充位的值未指定;没有必要保留,但填充位有两个重要的限制:

  1. 有符号整数中的正值应表示相同无符号类型的相同值。这保证了在签名变体范围内的正值的相同类型的有符号和无符号变体之间的兼容性。
  2. 如果所有位都为零,则表示值0。所以所有填充位也必须为0。然而,事实并非如此(感谢MattMcNabb)。
  3. 两个包括填充位,因为它们是内部表示的一部分。从更实际的角度来看,填充位应设置为零,除非存在依赖于其他位的奇偶校验位等(但必须满足第二个约束)。

    这是一个粗略的解释。有关详细信息,请参阅其他引用部分。

    在MSP430X上,20位int几乎没有实际用途。它们主要是为了扩展寻址范围,而不是整数算术(尽管指令集显然支持它 - 我在以前的编辑中错了)。

    指针有sizeof 32位(4个8位字节),但只使用20位。某些嵌入式编译器可能支持特殊的short / near / ...限定符,有效地提供了两种不同的指针大小。然而 - 这实际上违反了标准。 (我在这里有点矛盾:优化或可移植性)。

    MSP430X是使用stdint.huintptr_t)和stddef.h专用类型(例如size_t必需的专用类型的平台之一,因为投射指向/ int的指针最终会失败。更重要的是,标准对(u)intptr_t(临时存储,无操作)的唯一要求变得清晰。这样,无法保证填充位的任何内容 - 即使对于空指针也是如此。

    这种大开销(37.5%未使用位)的原因是MSP430X没有向存储器读取/写入20位甚至24位值(并且它会使阵列索引非常昂贵)的功能。只有一些常数可以是20位,因为它们在指令中使用包括4位的扩展字进行编码,其余16位用于其他指令,遵循OP代码。这可能是最后(小)架构之一,用于显示在保持兼容性的同时还需要为地址空间扩展做多少工作。

    请注意,MSP430X在20位寻址模式下还有一些额外的缺陷。例如,中断处理程序必须驻留在较低的64KiB中,因为向量表只包含16位条目。这实际上禁止将vetor表在C中定义为函数指针数组(因为它们不能自由地转换为任何其他函数指针并返回)。