【问题标题】:Is it always the case that sizeof(T) >= alignof(T) for all object types T?对于所有对象类型 T,sizeof(T) >= alignof(T) 是否总是如此?
【发布时间】:2018-03-09 12:09:58
【问题描述】:

对于任何对象类型T,是否总是sizeof(T) 至少与alignof(T) 一样大?

直觉上似乎是这样,因为即使您调整对象的对齐方式,例如:

struct small {
  char c;
};

在正常情况下,它们的“大小”也会向上调整,以便数组中对象之间的关系在保持对齐的同时有意义(至少在我的testing 中。例如:

struct alignas(16) small16 {
  char c;
};

大小和对齐方式均为 16。

【问题讨论】:

  • @tadman - 真正适用于任何架构。我在问标准保证或暗示什么。显然,在这两个示例中,sizeof(分别为 12 和 I*200)大于 alignof(分别为 1 和 I),其中 I 是 sizeof(I)。
  • @tadman - 这不是关于 x86 处理器的问题。当你说“这些将是一样的”时,“这些”是什么?
  • 好吧,如果您从假设开始,例如“float 是 4 个字节,sizeof( float ) 返回 4,但系统架构要求 float 位于 8 字节边界上” ,这会导致什么?副手,我认为这意味着float 的数组将被破坏。
  • @tadman 当然不是sizeof(T) == alignof(T) 的情况。很容易证明,例如struct S { char a,b; }; 通常有大小 2 和 alignof 1。我的问题是关于 >= 而不是 == 虽然......
  • ... 所以在硬件级别你可能有一些奇怪的东西,比如需要 16 字节对齐的 10 字节值,从 C++ 的角度来看,我认为这必须只是 sizeof 16。这就是为什么我要向@tadman 提供一个平台示例,其中 sizeof(long double) 小于 alignof(long double) - 因为这似乎不可能成为一个合规的实现!

标签: c++ c++11 memory-alignment alignof


【解决方案1】:

至少在标准 C++ 中,对于任何可以创建数组(长度 > 1)的东西,都必须是这样。如果你有

Foo arr[2];

alignof(Foo) > sizeof(Foo),那么arr[0]arr[1] 不能同时对齐。

不过,正如Zalman Stern's example 所示,至少有些编译器允许您声明对齐大于其大小的类型,结果编译器根本不允许您声明该类型的数组。这不是符合标准的 C++(它使用类型属性,即 are a GCC extension),但这意味着您可以在实践中使用 alignof(T) > sizeof(T)

数组参数假定sizeof(Foo) > 0,这对于标准支持的任何类型都是正确的,但o11c shows是编译器扩展破坏该保证的示例:一些编译器允许0长度数组,0sizeof和正数alignof.

【讨论】:

  • 我不确定是否存在此论点不适用的情况。可能是您根本无法创建实例的对象类型,或者是一个太大的类型,您无法在同一地址空间中容纳其中的两个?
  • 关于问题的 cmets 中的 Hans 似乎暗示允许 sizeof(Foo[2]) > 2*sizeof(Foo) 会破坏您的论点。我不知道我是否相信。
  • @user2357112 不能声明抽象类的数组,甚至不能声明单个实例。所以它的sizeof 不是很有用。
  • @curiousguy:嗯,您可以将抽象类的实例作为具体子类实例的基类子对象。不过,我认为没有任何方法可以获取它们的数组,因此这似乎是一个示例,即使没有编译器扩展,数组参数也会失败。
  • “我不知道这是否是严格符合的行为”——不是。 Zalman 的示例使用类型属性__attribute__ ((aligned (64)))。类型属性是 GCC extension,而不是 C 或 C++ 标准的一部分。我进行了编辑以澄清 - 希望没关系。
【解决方案2】:
#include <iostream>

typedef double foo __attribute__ ((aligned (64)));
alignas(64) double bar;
double baz __attribute__ ((aligned (64)));

int main(int argc, char *argv[]) {
    std::cout << "foo sizeof: " << sizeof(foo) << " alignof: " << alignof(foo) << "\n";
    std::cout << "bar sizeof: " << sizeof(bar) << " alignof: " << alignof(decltype(bar)) << "\n";
    std::cout << "baz sizeof: " << sizeof(baz) << " alignof: " << alignof(decltype(baz)) << "\n";
}

编译:

clang++ -std=c++11 alignof_test.cpp -o alignof_test && ./alignof_test

输出:

foo sizeof: 8 alignof: 64
bar sizeof: 8 alignof: 8
baz sizeof: 8 alignof: 8

所以严格来说,不,但是上面的参数 re: arrays 必须保留。

【讨论】:

  • 试试foo arr[2]; std::cout &lt;&lt; sizeof( arr ) &lt;&lt; "\n";
  • error: alignment of array elements is greater than element size,所以你不能把这些组成一个数组。我想知道这是否是严格遵守的行为。
  • 已更新以包括在实际 decl 上使用属性版本,这确实会崩溃。然而,Points 表示您可以创建违反约束的类型,这对于了解一个人是否依赖于此可能很重要,例如元编程。
  • __attribute__ ((aligned)) 是标准 C++ 吗?你能用alignof做同样的把戏吗?
  • __attribute__ 是 GCC 扩展。我还没有找到与alignof 获得相同结果的方法;我可以使用alignof(obj) &gt; sizeof(obj) 创建一个对象,但不能创建一个类型。
【解决方案3】:

根据引入alignof运算符的c++ 11 standardsizeof定义如下(见5.3.3 expr.sizeof):

sizeof 运算符产生其操作数的对象表示中的字节数

alignof 的定义是(参见 5.3.6 expr.alignof):

一个 alignof 表达式产生其操作数类型的对齐要求。

由于alignof 的定义指定了一个可能由用户提出的需求,而不是语言规范,我们可以操纵编译器:

typedef uint32_t __attribute__ ((aligned (64))) aligned_uint32_t;
std::cout << sizeof(aligned_uint32_t) << " -> " << alignof(aligned_uint32_t);
// Output: 4 -> 64

已编辑

正如其他人指出的那样,此类类型不能在数组中使用,例如尝试编译以下内容:

aligned_uint32_t arr[2];

error: alignment of array elements is greater than element size 中的结果

由于数组需要指定的类型符合条件:sizeof(T) &gt;= alignof(T)

【讨论】:

  • 是的,但请注意aligned_uinit32_t 不是一种类型,尽管您已命名它。它声明了一个具有不同对齐方式的堆栈变量。我知道在这种情况下,对齐是您要求的,并且 sizeof 不会改变。问题是你是否可以在任何地方使用这种行为来创建一个类型。
  • @BeeOnRope,你是对的,我不小心发布了中间代码。我已经调整了我的答案以表明可以以这种方式声明一个类型。
【解决方案4】:

许多编译器允许大小为0 的数组。对齐方式与唯一元素的对齐方式保持一致。

(除其他外,这对于在您无法使用位域的情况下强制进行特定对齐非常有用)

【讨论】:

  • 哦,是的,0 长度数组在某些编译器上是一个东西。 0 号螺丝的种类很多。
猜你喜欢
  • 2016-12-12
  • 1970-01-01
  • 2017-10-16
  • 2016-02-25
  • 2022-01-08
  • 2017-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多