据我所知,以下代码应该在定义int64_t
的平台的标准的任何合理读数下具有100%定义的行为,并且long long
具有相同的大小和表示,无论如何是否long long
被识别为别名兼容。
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef long long T1;
typedef int64_t T2;
#define T1FMT "%lld"
#define T1VALUE 1
#define T2VALUE 2
T1 blah3(void *p1, void *p2)
{
T1 *t1p, *t1p2;
T2 *t2p;
T1 temp;
t1p = p1;
t2p = p2;
*t1p = T1VALUE; // Write as T1
*t2p = T2VALUE; // Write as T2
temp = *t2p; // Read as T2
t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
*t1p2 = temp; // Write as T1
return *t1p; // Read as T1
}
T1 test3(void)
{
void *p = malloc(sizeof (T1) + sizeof (T2));
T1 result = blah3(p,p);
free(p);
return result;
}
int main(void)
{
T1 result = test3();
printf("The result is " T1FMT "\n", result);
return 0;
}
请参阅https://godbolt.org/g/75oLGx上的代码(GCC 6.2 x86-64,使用-std=c99 -x c -O2
)
test3
的正确代码应分配一些存储空间,然后:
long long
。int64_t
,将存储的有效类型设置为int64_t
。int64_t
(其有效类型),应该产生2 long long
,将存储的有效类型设置为long long
。long long
,应该产生2。然而,Godbolt网站上的gcc x86-64 6.2不会产生2;相反,它产生1.我没有找到gcc表现的任何其他类型的组合
像这样。我认为正在发生的事情是gcc决定可以省略* t1p2的商店,因为它没有效果,但它没有认识到商店确实具有从int64_t
更改存储的有效类型的效果到long long
。
虽然我认为不承认int64_t
和long long
是别名兼容的决定值得怀疑,但我认为标准中没有任何内容可以证明gcc未能识别存储的重用以保持在它之前保持值为1之后的值为2.除了写入它之外的任何类型都没有读取任何类型,但我认为gcc决定传递给“blah”的两个指针不能别名。
我错过了什么或者是一个彻头彻尾的错误吗?
答案 0 :(得分:0)
正如您所解释的,代码不违反严格别名规则。事实上,T1
和T2
可以是任何类型(这样的分配不是类型不匹配),它们不需要具有相同的大小或任何东西。
我同意输出1
是一个编译器错误。在godbolt网站上,所有版本的gcc似乎都有bug,而clang则提供正确的输出。
但是,使用gcc 4.9.2(x86_64-win32-seh-rev1)的本地安装,我得到2的正确输出。所以看起来这个问题只存在于gcc的某些版本中。