C99 和 C11 中的有效类型规则规定,没有声明类型的存储可以使用任何类型写入,并且存储非字符类型的值将相应地设置存储的有效类型。
撇开INT_MAX可能小于123456789这一事实不谈,以下代码对有效类型规则的使用是否严格符合?
#include <stdlib.h>
#include <stdio.h>
/* Performs some calculations using using int, then float,
then int.
If both results are desired, do_test(intbuff, floatbuff, 1);
For int only, do_test(intbuff, intbuff, 1);
For float only, do_test(floatbuff, float_buff, 0);
The latter two usages require storage with no declared type.
*/
void do_test(void *p1, void *p2, int leave_as_int)
{
*(int*)p1 = 1234000000;
float f = *(int*)p1;
*(float*)p2 = f*2-1234000000.0f;
if (leave_as_int)
{
int i = *(float*)p2;
*(int*)p1 = i+567890;
}
}
void (*volatile test)(void *p1, void *p2, int leave_as_int) = do_test;
int main(void)
{
int iresult;
float fresult;
void *p = malloc(sizeof(int) + sizeof(float));
if (p)
{
test(p,p,1);
iresult = *(int*)p;
test(p,p,0);
fresult = *(float*)p;
free(p);
printf("%10d %15.2fn", iresult,fresult);
}
return 0;
}
根据我对标准的阅读,注释中描述的函数的所有三种用法都应该严格符合(整数范围问题除外)。 因此,代码应输出1234567890 1234000000.00
. 但是,GCC 7.2 输出1234056789 1157904.00
. 我认为当leave_as_int
为 0 时,它会将 123400000 存储到 *p1
存储 123400000.0f 到 *p2
,但我在标准中看不到任何授权这种行为的内容。 我错过了什么,还是 gcc 不符合要求?
是的,这是一个 gcc 错误。我已经将其(带有简化的测试用例)作为 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82697 提交。
生成的机器代码无条件地写入两个指针:
do_test:
cmpl $1, %edx
movl $0x4e931ab1, (%rsi)
sbbl %eax, %eax
andl $-567890, %eax
addl $1234567890, %eax
movl %eax, (%rdi)
ret
这是一个 GCC 错误,因为所有存储都应该更改所访问内存的动态类型。 我不认为这种行为是标准规定的;它是海湾合作委员会扩展。
您可以提交 GCC 错误吗?