取消引用类型双关指针将破坏严格别名规则 [英] Dereferencing type-punned pointer will break strict-aliasing rules
问题描述
我使用以下代码从文件中读取数据,作为更大程序的一部分.
I used the following piece of code to read data from files as part of a larger program.
double data_read(FILE *stream,int code) {
char data[8];
switch(code) {
case 0x08:
return (unsigned char)fgetc(stream);
case 0x09:
return (signed char)fgetc(stream);
case 0x0b:
data[1] = fgetc(stream);
data[0] = fgetc(stream);
return *(short*)data;
case 0x0c:
for(int i=3;i>=0;i--)
data[i] = fgetc(stream);
return *(int*)data;
case 0x0d:
for(int i=3;i>=0;i--)
data[i] = fgetc(stream);
return *(float*)data;
case 0x0e:
for(int i=7;i>=0;i--)
data[i] = fgetc(stream);
return *(double*)data;
}
die("data read failed");
return 1;
}
现在我被告知使用 -O2
并且我收到以下 gcc 警告:警告:取消引用类型双关指针会破坏严格的别名规则
Now I am told to use -O2
and I get following gcc warning:
warning: dereferencing type-punned pointer will break strict-aliasing rules
谷歌搜索我发现了两个正交的答案:
Googleing I found two orthogonal answers:
对比
最后我不想忽略警告.你会推荐什么?
In the end I don't want to ignore the warnings. What would you recommend?
[更新] 我用真实的函数替换了玩具示例.
[update] I substituted the toy example with the real function.
推荐答案
看起来你真的很想用 fread:
It looks a lot as if you really want to use fread:
int data;
fread(&data, sizeof(data), 1, stream);
也就是说,如果您确实想走读取字符的路线,然后将它们重新解释为 int,那么在 C 中执行此操作的安全方法(但在 C++ 中不是)是使用 a工会:
That said, if you do want to go the route of reading chars, then reinterpreting them as an int, the safe way to do it in C (but not in C++) is to use a union:
union
{
char theChars[4];
int theInt;
} myunion;
for(int i=0; i<4; i++)
myunion.theChars[i] = fgetc(stream);
return myunion.theInt;
我不知道为什么原始代码中 data
的长度是 3.我假设你想要 4 个字节;至少我不知道任何 int 为 3 个字节的系统.
I'm not sure why the length of data
in your original code is 3. I assume you wanted 4 bytes; at least I don't know of any systems where an int is 3 bytes.
请注意,您的代码和我的代码都高度不可移植.
Note that both your code and mine are highly non-portable.
如果您想从文件中读取各种长度的整数,请尝试如下操作:
If you want to read ints of various lengths from a file, portably, try something like this:
unsigned result=0;
for(int i=0; i<4; i++)
result = (result << 8) | fgetc(stream);
(注意:在实际程序中,您还需要针对 EOF 测试 fgetc() 的返回值.)
(Note: In a real program, you would additionally want to test the return value of fgetc() against EOF.)
这会以小端格式从文件中读取一个 4 字节的无符号文件,不管系统的字节序是什么.它应该适用于任何无符号至少为 4 个字节的系统.
This reads a 4-byte unsigned from the file in little-endian format, regardless of what the endianness of the system is. It should work on just about any system where an unsigned is at least 4 bytes.
如果你想要字节序中立,不要使用指针或联合;改用位移.
If you want to be endian-neutral, don't use pointers or unions; use bit-shifts instead.
这篇关于取消引用类型双关指针将破坏严格别名规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!