【发布时间】:2020-02-13 05:55:34
【问题描述】:
给定以下代码
#include <cassert>
#include <climits>
#include <cstdint>
#include <iostream>
static_assert(CHAR_BIT == 8, "A byte does not consist of 8 bits");
void func1(const int32_t& i)
{
const unsigned char* j = reinterpret_cast<const unsigned char*>(&i);
for(int k = 0; k < 4; ++k)
std::cout << static_cast<int>(j[k]) << ' ';
std::cout << '\n';
}
void func2(const int32_t& i)
{
const unsigned char (&j)[4] = reinterpret_cast<const unsigned char (&)[4]>(i);
for(int k = 0; k < 4; ++k)
std::cout << static_cast<int>(j[k]) << ' ';
std::cout << '\n';
}
int main() {
func1(-1);
func2(-1);
}
从语言规则可以看出func1 是可以的,因为指向unsigned char 的指针可以为任何其他类型设置别名。我的问题是:这是否扩展到对已知长度的 C 数组的 C++ 引用?直觉上我会说是的。 func2 定义明确还是会触发未定义的行为?
我已经尝试使用 Clang 和 GCC 以及 -Wextra -Wall -Wpedantic 和 UBSAN 的所有可能组合来编译上述代码,并且没有收到任何警告并且始终得到相同的输出。这显然没有说明没有 UB,但我无法触发任何通常的严格别名类型优化错误。
【问题讨论】:
-
我的猜测(我不敢将此作为答案发布)是没有 UB假设
int32_t的定义已验证。也就是说,只要这是一个 4 字节(即 4 个字符)连续的内存块,就没有问题。 -
这就是我使用
int32_t而不仅仅是int的原因(因为这可能会引发有关sizeof(int) != 4的情况的问题,例如在DOS 等上) -
@Adrian 7.20.1.1 Exact-width integer types from the C standard 是相关的:“typedef 名称
intN_t指定宽度为N、无填充位和二进制补码表示的有符号整数类型。”如果int32_t存在,它似乎必须是连续的。不过,在这种情况下,“字节”仍然可以是 8、16 或 32 位。 -
@JonasMüller 但 sizeof(int32_t) 也不一定是 4,因为 char 不一定是 8 位。此外,sizeof(int32_t) 不像 4 那样是一个幻数,所以最好使用它。
-
@JonasMüller:“从语言规则来看,
func1很好”。事实上,不完全是,j[0]可以,j + 1可以。但是j[1]和j[2]是迂腐的UB,因为j没有指向array(与func2相反:-))。
标签: c++ language-lawyer undefined-behavior strict-aliasing