Oli*_*ock 5 c++ strict-aliasing undefined-behavior language-lawyer
外部 API 需要一个指向值数组(此处为 int 作为简单示例)的指针加上一个大小。
以 4 为一组处理元素在逻辑上更清晰。
因此,通过“4 组”结构处理元素,然后使用指针转换将这些结构的数组传递到外部 API。请参阅下面的代码。
蜘蛛感知说:=> 可能的 UB 中存在“严格混叠违规” reinterpret_cast
?
以下内容static_asserts
是否足以确保:a) 这在实践中有效 b) 这实际上符合标准而不是 UB?
否则,我需要做什么,才能使其“不是UB”。工会?请问具体怎么样?
或者,是否有一种不同的、更好的方法?
#include <cstddef>
void f(int*, std::size_t) {
// external implementation
// process array
}
int main() {
static constexpr std::size_t group_size = 4;
static constexpr std::size_t number_groups = 10;
static constexpr std::size_t total_number = group_size * number_groups;
static_assert(total_number % group_size == 0);
int vals[total_number]{};
struct quad {
int val[group_size]{};
};
quad vals2[number_groups]{};
// deal with values in groups of four using member functions of `quad`
static_assert(alignof(int) == alignof(quad));
static_assert(group_size * sizeof(int) == sizeof(quad));
static_assert(sizeof(vals) == sizeof(vals2));
f(vals, total_number);
f(reinterpret_cast<int*>(vals2), total_number); /// is this UB? or OK under above asserts?
}
Run Code Online (Sandbox Code Playgroud)
再多的static_assert
s 也无法使UB 的东西变成符合标准的明确定义的行为。您没有创建 s 数组int
;您创建了一个包含int
s 数组的结构。这就是你所拥有的。
将指向 a 的指针转换quad
为指向 an 的指针是合法的int[group_size]
(尽管您需要适当地更改代码。或者您可以直接访问数组并将其转换为int*
.
无论如何获得指向第一个元素的指针,在该数组中进行指针算术都是合法的。但是,当您尝试在该对象内quad
的数组边界之外进行指针算术时,就会实现未定义的行为。指针运算是根据数组的存在来定义的:[expr.add]/4
\n\n当整型表达式 J 与指针类型表达式 P 相加或相减时,结果的类型为 P。
\n\n
\n- 如果 P 的计算结果为空指针值且 J 的计算结果为 0,则结果为空指针值。
\n- 否则,如果 P 指向具有 n 个元素的数组对象 x ([dcl.array]) 的数组元素 i,则表达式 P + J 和 J + P(其中 J 的值为 j)指向(可能假设的) x 的数组元素 i+j if 0\xe2\x89\xa4i+j\xe2\x89\xa4n 并且表达式 P - J 指向 x 的(可能是假设的)数组元素 i\xe2\x88\x92j if 0\xe2\x89\xa4i\xe2\x88\x92j\xe2\x89\xa4n。
\n- 否则,行为是未定义的。
\n
指针不为空,因此情况 1 不适用。上面n
是group_size
(因为数组是 内的数组quad
),所以如果索引是 > group_size
,则情况 2 不适用。
因此,每当有人尝试访问索引 4 之后的数组时,都会发生未定义的行为。没有任何强制转换可以覆盖它。
\n\n\n否则,我需要做什么,才能使其“不是UB”。工会?请问具体怎么样?
\n
你不知道。您尝试做的事情对于 C++ 对象模型来说根本无效。您需要一个 s 数组int
,因此必须创建一个int
s 数组。您不能将除 s 之外的其他数组int
视为 s 数组int
(好吧,除了字节数组的少数例外,但这对您没有帮助)。
分组处理数组的最简单有效方法就是......执行一些嵌套循环:
\nint arr[total_number];\nfor(int* curr = arr; curr != std::end(arr); curr += 4)\n{\n //Use `curr[0]` to `curr[3]`;\n //Or create a `std::span<int, 4> group(curr)`;\n}\n
Run Code Online (Sandbox Code Playgroud)\n