外部API需要一个指向值数组的指针(这里的简单示例是int)加上一个大小。
以4个元素为一组处理这些元素在逻辑上更清楚。
因此,通过一个“4个一组”结构体处理元素,然后使用指针强制转换将这些结构体的数组传递给外部API。
蜘蛛感说:reinterpret_cast
=〉可能UB中的“严格混叠违规”?
1.以下static_asserts
是否足以确保:a)这在实践中有效B)这实际上符合标准,而不是UB?
1.否则,我需要做什么,让它“不是UB”。工会?请具体怎么做?
1.或者,总体上有没有一种不同的,更好的方式?
#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?
}
2条答案
按热度按时间8iwquhpp1#
不,这是不允许的。相关的C++标准节是§7.6.1.10。从第一段开始,我们有(强调我的)
表达式
reinterpret_cast<T>(v)
的结果是将表达式v
转换为类型T
的结果,如果T
是对函数类型的左值引用类型或右值引用,则结果为左值;如果T
是对对象类型的右值引用,则结果是x值;否则,结果是一个纯右值,并且对表达式v
执行左值到右值、数组到指针和函数到指针的标准转换。下面列出了可以显式使用reinterpret_Çcast执行的转换。没有其他转换可以显式使用reinterpret_Çcast执行。因此,除非你的用例列在特定的页面上,否则它是无效的。大多数部分与你的用例无关,但这是最接近的一个。
一个对象指针可以显式地转换成不同类型的对象指针。[58]当对象指针类型的纯右值
v
被转换成对象指针类型“指针到cv T
“时,结果是static_cast<cv T*>(static_cast<cv void*>(v))
。所以
reinterpret_cast
从一个指针类型到另一个指针类型等价于static_cast
通过一个适当的cv限定的void*
,现在,如果类型T
和S
是 * 指针可互换的 *,那么从T*
到S*
的static_cast
可以被接受地用作S*
。两个对象a和b是指针可互换的,如果:
如果两个对象是指针可互换的,那么它们有相同的地址,并且可以通过reinterpret_Çcast([expr.reinterpret.cast])从指向一个对象的指针获得指向另一个对象的指针。
[Note 4:数组对象和它的第一个元素不能指针互换,即使它们有相同的地址。
总而言之,如果没有vtable可以阻止你,你可以将指向类
C
的指针强制转换成指向它的第一个成员的指针(然后返回);你可以将指向C
的指针强制转换成指向C
的另一个指针(如果你添加了cv限定符;例如,如果my_c_ptr
是C*
,则reinterpret_cast<const C*>(my_c_ptr)
是有效的)。对于联合,还有一些特殊的规则,这些规则在这里不适用。* 然而 ,您不能通过数组进行因子分解,如注解4所述。您 * 想要 * 的转换在这里是quad[] -> quad -> int -> int[]
,你不能在quad[]
和quad
之间转换,如果quad
是一个简单的结构体,只包含一个int
,那么你可以把quad*
重新解释为int*
,但是你不能通过数组来实现,当然也不能通过它们的嵌套层。我引用的章节中没有一个提到对齐、大小、压缩或填充,这些都不重要。你的
static_assert
所做的只是稍微增加未定义行为( 仍然 * 未定义)在更多编译器上发生作用的可能性。但是你是在用绷带修补大坝;这是行不通的。jaxagkaj2#
再多的
static_assert
s也不能使某个 * 绝对 * UB的东西变成符合标准的定义良好的行为。你创建了一个包含int
数组的结构体,这就是你所拥有的。将指向
quad
的指针转换为指向int[group_size]
的指针是合法的(尽管需要适当地修改代码,或者直接访问数组并将其转换为int*
)。不管你如何得到指向第一个元素的指针,在数组中进行指针运算都是合法的,但是当你试图在
quad
* 对象中进行指针运算超出数组边界的时候,你就得到了未定义的行为,指针运算是基于数组的存在而定义的:[表达式添加]/4当将具有整数类型的表达式J添加到指针类型的表达式P中或从中减去时,结果具有P的类型。
指针不为空,所以第一种情况不适用,上面的
n
是group_size
(因为数组是quad
中的一个),所以如果索引〉group_size
,那么第二种情况不适用。因此,每当有人试图访问索引4之后的数组时,就会发生未定义的行为。没有任何强制转换可以覆盖这一行为。
否则,我需要做什么,让它"不是UB"。工会?请具体怎么做?
你不需要。你试图做的事情对于C++对象模型是无效的。你需要一个
int
的数组,所以你必须创建一个int
的数组。你不能把int
以外的数组当作int
的数组(当然,字节数组是个小例外,但这对你没有帮助)。分组处理数组的最简单 * 有效 * 的方法是......执行一些嵌套循环: