【发布时间】:2013-07-18 11:28:06
【问题描述】:
有几个来自严格别名的错误,所以我想我会尝试修复所有这些错误。仔细研究了它是什么,有时 GCC 似乎不会发出警告,而且有些事情是不可能实现的。至少根据我的理解,下面的每一个都被打破了。那么我的理解是错误的,是否有正确的方法来做所有这些事情,或者某些代码只需要在技术上打破规则并被系统测试很好地覆盖?
错误来自一些混合了 char 和 unsigned char 缓冲区的代码,例如如下:
size_t Process(char *buf, char *end)
{
char *p = buf;
ProcessSome((unsigned char**)&p, (unsigned char*)end);
//GCC decided p could not be changed by ProcessSome and so always returned 0
return (size_t)(p - buf);
}
将其更改为以下似乎可以解决问题,尽管它仍然涉及强制转换,所以我不确定为什么它现在有效并且没有警告:
size_t Process(char *buf, char *end)
{
unsigned char *buf2 = (unsigned char *)buf;
unsigned char *p = buf2;
unsigned char *end2 = (unsigned char*)end;
ProcessSome(&p, end2);
return (size_t)(p - buf2);
}
还有很多其他地方似乎在没有警告的情况下工作
//contains a unsigned char* of data. Possibly from the network, disk, etc.
//the buffer contents itself is 8 byte aligned.
const Buffer *buffer = foo();
const uint16_t *utf16Text = (const uint16_t*)buffer->GetData();//const unsigned char*
//... read utf16Text. Does not even seem to ever be a warning
//also seems to work fine
size_t len = CalculateWorstCaseLength(...);
Buffer *buffer = new Buffer(len * 2);
uint16_t *utf16 = (uint16_t*)buffer->GetData();//unsigned char*
len = DoSomeProcessing(utf16, len, ...);
buffer->Truncate(len * 2);
send(buffer);
还有一些...
struct Hash128
{
unsigned char data[16];
};
...
size_t operator ()(const Hash128 &hash)
{
return *(size_t*)hash.data;//warning
}
非字符大小写。这没有警告,即使它很糟糕,我该如何避免它(两种方法似乎都有效)?
int *x = fromsomewhere();//aligned to 16 bytes, array of 4
__m128i xmm = _mm_load_si128((__m128*i)x);
__m128i xmm2 = *(__m128i*)x;
查看其他 API 似乎也有各种情况,据我了解,这些情况违反了规则(没有遇到 Linux/GCC 特定的情况,但肯定会在某个地方出现)。
CoCreateInstance 有一个需要显式指针转换的 void** 输出参数。 Direct3D 也有类似的。
LARGE_INTEGER 是一个联合体,可能会对不同的成员进行读/写(例如,某些代码可能使用高/低,然后其他一些可能会读取 int64)。
我记得 CPython 实现非常高兴地将 PyObject* 投射到一堆其他的东西上,这些东西在开始时恰好具有相同的内存布局。
我见过的很多哈希实现会将输入缓冲区转换为 uint32_t*,然后可能使用 uint8_t 来处理最后的 1-3 个字节。
我见过的几乎所有内存分配器实现都使用 char* 或 unsigned char*,然后必须将其强制转换为所需的类型(可能通过返回的 void*,但在分配内部至少它是字符)
【问题讨论】:
-
您的第一个示例是否真的表现出总是返回零的行为,或者它只是类似于这样做的代码?我无法重现这种行为。
-
差不多就是这样,只是函数名称不同。这是针对 x64 的经过修改的企业红帽上的 gcc 4.4.5。然而,所有内容都被内联了,因此它可能非常具体地说明 GCC 决定如何优化整体。
标签: c++ gcc strict-aliasing