是否 sizeof(T) == sizeof(const T) 和 alignof(T) == alignof(const T)

Posted

技术标签:

【中文标题】是否 sizeof(T) == sizeof(const T) 和 alignof(T) == alignof(const T)【英文标题】:Does sizeof(T) == sizeof(const T) and alignof(T) == alignof(const T) 【发布时间】:2016-12-12 12:00:20 【问题描述】:

假设Tconst T 是两个大小相同且对齐方式相同的类型似乎是合理的,但在考虑了一些实际系统之后,它们似乎可能会有所不同。

让我解释一下:

假设您的系统具有两种类型的内存:RAM 和闪存(只读)。 RAM 是 8 位可寻址的,而 Flash 只能是 16 位可寻址的。假设这是T

struct T

  uint8_t x;
  uint16_t y;
;

在字节可寻址 RAM 中,此结构体的长度为 3 个字节......但在双字节可寻址闪存(const 变量所在的位置)中,此结构体必须至少为 4 个字节长,因为对齐问题。

所以这是我的问题:

c 和 c++ 标准是否保证const 和非const 类型的大小和对齐方式?

【问题讨论】:

你做了很多没有人能保证的假设。无论如何,大多数 RAM 与闪存的东西都来自您的链接器脚本。 @JonathonReinhart 因此问题 这个问题很棘手。答案是“是的,它们必须是相同的大小”,但是,flash notconst variable would reside。可能是你在那里放了很多 const 值,但 const 没有意思是flash。特别是我可以有一个函数调用的const int参数,它将在堆栈上,而不是在flash中。最后,我相信这样的系统违反了同质的C内存模型,所以它的行为将是编译器扩展。 请注意,像您描述的那种花哨的硬件通常带有自定义的、不符合标准的编译器,这些编译器能够以不符合标准为代价来利用全部硬件潜力标准中的一些细节......所以如果你真的需要使用 Flash v RAM 的东西,你仍然可以使用不符合标准的编译器。 @CortAmmon 我不同意你的说法“我相信这样的系统违反了同质的 C 内存模型”。是的,C 有一个同质的抽象内存模型,但 C 标准不要求实现具有同质内存,只要求它act 像它一样。编译器可以绕过这个问题(以优化为代价)并表现得像它具有同质内存的一种方法是使所有 Ts 长 4 个字节,并且指向 T 的指针中有一个特殊位指示它是位于闪存还是 RAM ..... 【参考方案1】:

在字节可寻址 RAM 中,这个结构将是 3 个字节长....但是 在双字节可寻址闪存中(这是一个 const 变量 将驻留)此结构必须至少有 4 个字节长, 因为对齐问题。

但是,编译器不能推断仅仅因为这里是const,它就存储在ROM中。还有很多其他的东西可以防止这种情况发生,比如mutable,或者您可以动态地将const T 放在堆栈上,或者手动将其放入RAM 中的堆内存或其他一千种东西中。你也可以有一个const T&,它可以在任何一个位置。

【讨论】:

这是很好的信息。请记住,const保证在 ROM/Flash 中的位置,尽管这通常是您想要的。 好吧,mutable 是相关的,因为 const 对象内的可变字段可以修改,因此不能驻留在 ROM 中。【参考方案2】:

第 3.9.3 节:

一个类型的 cv 限定或 cv 非限定版本是不同的 类型;但是,它们应具有相同的表示和对齐方式 要求 (3.11)。 53

这里的“cv-qualified”指的是constvolatile。所以答案是肯定的。

constvolatile 仅指定对指定对象的访问限制/属性。它们不被认为是基本类型本身的一部分;因此它们不会影响类型的属性。

【讨论】:

所以在我的示例中,sizeof(T) 将被强制为 4 以匹配 const T? 对于 C,它是 6.2.5/26(在 C11 中),除了拼写是 _Alignof @DarthRubik 与 Sam 不同,我不确定接下来会发生什么。编译器也可以强制将对象存储在允许不太严格的 3 字节对齐的内存区域中。当然,这实际上意味着在您的示例中不允许使用闪存 - 但我认为这并不像听起来那么奇怪;我似乎记得 Arduino 需要以定义的单位对 Flash 中的数据进行特殊序列化。唯一的一点是编译器不能分配不同的 cv 限定的化身,从而使提到的属性不同。我不会急于总结如何它必须这样做。 @underscore_d 如果您使用avr-gcc(这是arduino 使用的),gcc 会尝试将const 变量放入闪存中,但使用FLASHCONST 可以保证这一点。【参考方案3】:

是的,这是由 [basic.type.qualifier] / 1 保证的

类型的 cv 限定或 cv 非限定版本是不同的类型;但是,它们应具有相同的表示和对齐要求 (3.11)。

【讨论】:

以上是关于是否 sizeof(T) == sizeof(const T) 和 alignof(T) == alignof(const T)的主要内容,如果未能解决你的问题,请参考以下文章

sizeof(T) 和 Unsafe.SizeOf<T>() 有啥区别?

将 operator new(sizeof(T) * N) 返回的内存视为数组

对象表示和运算符 sizeof 的定义

sizeof(long) == sizeof(void*) 吗?

t=(char*)malloc(n*sizeof(char))的含义?

是否存在 sizeof(char) != 1 或至少 CHAR_BIT > 8 的机器?