关于类型双关语的问题:为什么这段代码会破坏严格的别名规则:
int main()
{
int a = 1;
short j;
printf("%i\n", j = *((short*)&a));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这不是:
int main()
{
int a = 1;
short j;
int *p;
p=&a;
printf("%i\n", j = *((short*)p));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
建设者gcc -fstrict-aliasing.
谢谢!
我正在使用HIDAPI将一些数据发送到USB设备.这个数据只能作为字节数组发送,我需要在这个数据数组中发送一些浮点数.我知道浮点数有4个字节所以我认为这可能有用:
float f = 0.6;
char data[4];
data[0] = (int) f >> 24;
data[1] = (int) f >> 16;
data[2] = (int) f >> 8;
data[3] = (int) f;
Run Code Online (Sandbox Code Playgroud)
后来我所要做的就是:
g = (float)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]) );
Run Code Online (Sandbox Code Playgroud)
但测试这一点告诉我,像float返回的线总是4.我的代码出了什么问题,我怎么能正确地做到这一点(即在4个字节字节中打破浮点内部数据并在以后重建同一个浮点数)?
编辑:
我能够用以下代码完成此任务:
float f = 0.1;
unsigned char *pc;
pc = (unsigned char*)&f;
// 0.6 in float
pc[0] = 0x9A;
pc[1] = 0x99;
pc[2] = 0x19;
pc[3] = 0x3F; …Run Code Online (Sandbox Code Playgroud) 我回答了对我的回答的评论:C求职面试 - 演员和比较,发现我找不到C++认为"实施定义行为"的完整列表.我知道这类事情有3个类别:未定义的行为,实现定义的行为和未指定的行为; 然而,似乎大多数讨论都围绕未定义的行为,并且当讨论实现定义的行为时,最多给出一个例子.一般来说,我倾向于编写很多代码来捕获这个区域,我知道会发生什么样的行为; 我仍然希望能够对其有效性发表评论.我还想抛弃那里,我认为操作社区中有很多误诊是未定义的,而实际上它们是由平台很好地定义的.
请注意,我对给定平台如何选择定义此类行为并不感兴趣,而是对包含C++标准定义的"实现定义"类别中的所有行为的列表感兴趣.
我已经阅读了许多有关此警告的问题(取消引用类型双关指针会破坏严格别名规则,取消引用类型双关指针会破坏严格别名规则 [-Wstrict-aliasing],严格别名规则是什么?,“取消引用类型双关指针将破坏严格的别名规则”警告和其他人)并且对我的警告完全感到困惑。
所以我有一个结构:
typedef struct {
unsigned char precision;
unsigned char scale;
unsigned char array[33];
} DBNUMERIC;
Run Code Online (Sandbox Code Playgroud)
当从 MS SQL Server 检索数据时,该结构由 FreeTDS 库填充。我知道从array[1]那里开始是 64 位整数(大端),我想得到它。我使用以下代码:
int64_t result = 0;
result = be64toh(*((decltype(result)*)(numeric.array + 1)));
Run Code Online (Sandbox Code Playgroud)
但是 GCC 给了我警告dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]。但是如果我使用代码:
int64_t result = 0;
decltype(result)* temp_ptr = (decltype(result)*)(numeric.array + 1);
decltype(result) temp = *temp_ptr;
result = be64toh(temp);
Run Code Online (Sandbox Code Playgroud)
没有关于违反严格别名规则的警告。我不认为此代码与原始代码不同,因此我很困惑。如何将数组中的 8 个字节转换为int64_t变量?
请考虑以下代码.它没问题还是会导致未定义的行为?
#include <iostream>
int main()
{
{
unsigned char binary[] = {0, 5, 10};
bool* x = reinterpret_cast<bool*>(&binary[0]);
for (unsigned int i = 0; i < 3; ++i)
{
std::cout << (x[i] ? 1 : 0) << " ";
}
}
{
unsigned char b = 255;
bool* x = reinterpret_cast<bool*>(&b);
std::cout << (*x ? 1 : 0) << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用gcc 4.6到4.8编译时的输出是
0 5 10 1
但只有优化(-O1和更多).Clang导致
0 1 1 1
即使有优化.现在,如果更改y[i] ? …
在C++中,有些东西出现在明确定义和未定义之间.具体而言,这些被称为实现定义和未指定.现在,我对未指明的东西很感兴趣.
什么时候可以使用这些功能,什么时候应该避免?是否有正确代码的未指定行为的良好示例?在编写软件时,它是否是最佳选择?
Matt McNabb提供的定义:
未定义 - 任何事情都可能发生
实现定义 - 有限数量的结果是可能的,编译器的文档必须说明会发生什么
未指定 - 可能有限数量的结果 - 通常标准描述了可能结果的集合
定义明确 - 以上都不是
格式良好的程序 - 无错误编译的程序(可能表现出未定义的行为)
后续问题:
放松的原子是否被指定为未指定或明确定义?