【问题标题】:How to check if an alignment is valid in C?如何检查对齐在C中是否有效?
【发布时间】:2016-03-25 22:30:01
【问题描述】:

我正在编写的代码需要完全符合标准。该标准不承诺任何比max_align_t 更强的对齐选项。我想尝试与缓存行对齐,但我知道如果实现不支持这种强度的对齐方式,那将是未定义的行为。

有没有办法解决这个问题?有什么方法可以在预处理时检查哪些扩展对齐可用?或者,如果对齐不可用,有什么方法可以请求对齐,而不是得到它,而不是有未定义的行为?

aligned_alloc 适用于分配的内存。不过,我也对静态存储的内存感兴趣。

编辑: 为了说明我的问题,以下是我遇到问题的 C11 标准的陈述:

6.2.8

  1. 对齐表示为size_t 类型的值。有效对齐仅包括由基本类型的_Alignof 表达式返回的值,以及附加的实现定义的值集,这些值可能为空。每个有效的对齐值都应该是 2 的非负整数幂。

因此,任何给定的 2 幂都不一定是有效的对齐方式,我不能指望 64 小于或等于 max_align_t,因此 64 可能不是有效的对齐方式。如果它不是有效的对齐方式,这是我未定义的行为问题:

6.7.5 对齐说明符

  1. 常量表达式应为整数常量表达式。它应评估为有效的基本对齐,或在其出现的上下文中由实现支持的有效扩展对齐,或为零。

【问题讨论】:

  • 不确定您的问题是什么,特别是当您使用 C11 标签时。 _Alignas_ 使用您指定的对齐方式。如果您使用非法对齐,您将调用 UB,但它仍用于对象。问题是什么?并且预处理是在处理之前完成的(查找前缀“pre”),那么它是如何进入游戏的呢?
  • 问题是未定义的行为。我需要保证不会有未定义的行为,因此我无法与有可能产生未定义行为的对齐方式对齐。无法保证像 64 这样良性的东西会成为合法的对齐方式。
  • 嗯,你应该阅读关于对齐的想法。您能否详细说明为什么所需对齐的更大倍数会成为问题?
  • 1.预处理器肯定不会有帮助。 2. 如果 _Alignas_ 不符合您的要求,您可以随时分配(也静态)更大的内存块,并根据您的喜好在该内存块内工作。这完全独立于编译器和系统。这是否会提高代码的可读性和可维护性,我将留给您...在大多数情况下,您最好使用动态内存和 aligned_alloc()
  • @tofro 1. 如果我能确定它不会产生定义的行为,我希望使用预处理器来放弃我的对齐请求。例如,如果 max_align_t 与 64 字节对齐(我怀疑永远不会如此),那么我可以使用该信息来证明可以包含我的 64 字节对齐。 2. 感兴趣的代码是一个头文件,它声明了许多我想使用相同内存的类似函数,并且我希望它缓存行对齐,都是出于性能考虑。分配会在使用函数时引入不希望的复杂性。

标签: c memory-alignment c11


【解决方案1】:

您的编译器将自行选择的对齐方式不应该比max_align_t 更宽,但这就是它的全部。要求更广泛的对齐是没有障碍的。

因此,要确保struct 的特定字段按您的意愿放置在边界上,您只需使用_Alignas。只要您要求的值是 2 的幂,并且您的编译器允许特定的对齐方式,所有内容都已明确定义。如果不是,你的编译器必须抱怨。

这正是在 C11 中添加 _Alignas 的原因之一。

【讨论】:

  • 仅仅让一个阵营成为 2 次方不足以形成一个有效阵营。我将标准中的引号添加到我的问题中以支持这一点。所以,我的问题是我只想要求 2 次幂,如果没有提供,那很好。这可能就是未定义的行为。尽管如此,我仍然会依赖未定义的行为,这对我的项目来说是不可接受的。
  • 不,标准文本中的“shall”通常命名约束。因此,如果您选择的对齐方式不在扩展对齐方式中,您的编译器必须 给出诊断。特别是,这样的代码要么编译(然后行为被明确定义),要么编译失败并出现诊断。如果您考虑一下,这里有“未定义的行为”是没有意义的。类型及其对齐方式是编译时特性。因此,如果出现问题,编译器应该会告诉你。
  • 太棒了,谢谢。我没有意识到“应该”对实施提出了如此明确的要求。我在标准中找到了这些要求的描述,所以很高兴知道。
【解决方案2】:

我认为,您需要查看函数 valloc()memalign()。 另外,非常有用的调用:

int pagesize = sysconf(_SC_PAGESIZE);

如果您需要将缓冲区与页面大小对齐,您可以调用:

char *buf = ...; // Buffer to unaligned memory
buf -= (uinsigned)buf & (pagesize - 1); // align to low border
buf += pagesize; // align to high border

【讨论】:

  • 无论uinsigned 是什么,这是一个非常糟糕(且不必要)的黑客行为。 OP 清楚地询问了一种符合标准的方式,而您的代码绝对不是。他主要询问静态对象。
猜你喜欢
  • 2010-10-29
  • 2016-05-25
  • 1970-01-01
  • 2013-06-03
  • 2016-05-07
  • 2013-10-11
  • 1970-01-01
  • 2012-03-15
  • 2021-10-12
相关资源
最近更新 更多