这是gcc 6.2中的存储重用(别名)错误吗?
据我所知,对于定义这是gcc 6.2中的存储重用(别名)错误吗?,gcc,strict-aliasing,Gcc,Strict Aliasing,据我所知,对于定义int64_t的平台,无论long是否被识别为别名兼容,以下代码在任何合理的标准阅读下都应该具有100%的定义行为,并且long具有相同的大小和表示形式 #include <stdint.h> #include <string.h> #include <stdlib.h> #include <stdio.h> typedef long long T1; typedef int64_t T2; #define T1FMT "%ll
int64_t
的平台,无论long
是否被识别为别名兼容,以下代码在任何合理的标准阅读下都应该具有100%的定义行为,并且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;
}
#包括
#包括
#包括
#包括
typedef长T1;
typedef int64_t T2;
#定义T1FMT“%lld”
#定义T11值
#定义T22值
T1 blah3(无效*p1,无效*p2)
{
T1*t1p,*t1p2;
T2*t2p;
T1温度;
t1p=p1;
t2p=p2;
*t1p=T1VALUE;//写入为T1
*t2p=T2VALUE;//写入为T2
temp=*t2p;//读作T2
t1p2=(T1*)t2p;//可见T2到T1指针的转换
*t1p2=temp;//写入为T1
return*t1p;//读作T1
}
T1测试3(无效)
{
void*p=malloc(sizeof(T1)+sizeof(T2));
T1结果=blah3(p,p);
自由基(p);
返回结果;
}
内部主(空)
{
T1结果=test3();
printf(“结果为“T1FMT”\n”,result);
返回0;
}
参见第页的代码(GCC 6.2 x86-64使用-std=c99-x c-O2
)
测试3的正确代码应该分配一些存储空间,然后:
long
int64\u t
,将存储器的有效类型设置为int64\u t
int64\u t
(其有效类型),应产生2long-long
,将存储的有效类型设置为long
long
,这将产生2int64\t
更改为long
的效果
虽然我认为不承认<代码> ITS64×T< <代码>和<代码>长Lo/<代码>作为别名兼容,但我看不出标准中的任何东西都能证明GCC在存储值1之后无法识别存储的重用以保持值2。除了编写时使用的类型外,任何类型都不能被读取,但我认为gcc决定传递给“blah”的两个指针不能使用别名
我是否遗漏了什么,或者这是一个彻底的错误?正如您所解释的,代码没有违反严格的别名规则。事实上,
T1
和T2
可以是任何类型(这样分配就不是类型不匹配),它们不需要有相同的大小或任何东西
我同意输出1
是一个编译器错误。在godbolt站点上,所有版本的gcc似乎都有这个bug,而clang提供了正确的输出
但是,通过本地安装GCC4.9.2(x86_64-win32-seh-rev1),我得到了正确的输出2。因此,问题似乎只存在于gcc的某些版本中。据我所知,出现此错误的一个关键条件是编译器必须(错误地)将
*t1p2
的存储视为不可操作。我不知道是否所有gcc安装都对int64\t
使用相同的定义,由于在将该类型指定为long
的平台上,此处的代码可以正常工作,如图所示,但如果将T1更改为long
,则代码将失败。我想知道该标准的作者是否曾想过,任何高质量的编译器都不会识别具有相同大小和表示形式的类型之间的别名,因为无法识别别名可能会使在使用不同命名类型的API之间以定义的方式交换数据变得非常困难?在任何情况下,我认为发生的事情是gcc决定写入为T2
不会因为其类型而影响*t1p
,而写入为T1
不会影响它,因为它只是写入了“已经写入的内容”(即使之前的写入被忽略)。@supercat似乎是合理的,我想这可以通过深入研究优化器代码来证实