严格别名char *到更宽泛的类型,没有未定义的行为

时间:2016-09-22 16:43:28

标签: c++

我对这是否是严格的别名违规或调用未定义的行为感到困惑。多人告诉我这不是违规,并且没有UB,但是从阅读C ++规范听起来像是在做任何取消引用类型转换指针(除非它只是cv-casted或转换为兼容类型或char)是UB。

SWAP

https://godbolt.org/g/DIXtJX

(这是一个有点人为的例子;实际上uint16_t可能是需要char的第三方函数。)

故事是否因为我们检查了对齐而变化,对类型的大小有信心并且不关心字节序?我想,剩下的问题将是优化器消除死代码。

如果这是非法的,您如何有效地将int16缓冲区(例如来自文件)解释为其预期类型(例如=INDEX(A1:A100,SUMPRODUCT(--(C1:C100=MAX(IF(B1:B100="fruit",C1:C100,"")))*(B1:B100="fruit")*ROW(1:100))) s)?我很熟悉通过联合进行转换,但我并没有真正看到它有何不同(参见casting through a union(1),除了告诉编译器它不能消除死代码。

2 个答案:

答案 0 :(得分:4)

  

多人告诉我,这不是违规,而且没有UB

那些人错了。这段代码:

uint16_t* data16 = reinterpret_cast<uint16_t*>(data);

是已定义的行为,如果,且仅当时,uint16_t处有data类型的对象。也就是说,如果我把你的foo称为:

uint16_t p = 42;
foo(reinterpret_cast<char*>(&p), 2); // now, we're ok

或:

char data[64];
new (data) uint16_t{42};
foo(data, 2); // also ok, though with C++17 you'll have to use std::launder

但除此之外,它是UB。非UB的方法是:

uint16_t data16;
memcpy(&data16, data, sizeof(data16));

许多编译器将其视为reinterpret_cast

也就是说,大量的网络代码正在做你正在做的事情,如果编译器以一种导致它的方式对这些代码进行优化,那么街道上会发生暴乱许多愤怒的消息不做你想要的。

答案 1 :(得分:1)

  

执行取消引用类型转换指针的任何(除非它只是cv-casted或转换为兼容类型或char)是UB。

这是不正确的。

任何指针都可以转换为char*void*并返回。仅当原始指针的类型与解除引用指针时使用的指针类型不同时,它才是UB。甚至有例外。有关示例,请参阅Struct alignment and type reinterpretation