这种有效类型规则的使用是否严格符合?

时间:2017-10-05 18:04:53

标签: c gcc undefined-behavior c99 strict-aliasing

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.2f\n", iresult,fresult);
  }
  return 0;
}

从我对标准的阅读中,评论中描述的函数的所有三种用法都应该严格符合(整数范围问题除外)。因此代码应输出1234567890 1234000000.00。但是,GCC 7.2输出1234056789 1157904.00。我认为当leave_as_int为0时,它会将123400000存储到*p1,然后将123400000存储到*p2,但我在标准中没有看到任何授权此类行为的内容。我错过了什么,或者gcc不合规?

2 个答案:

答案 0 :(得分:1)

是的,这是一个gcc错误。我已将其(使用简化的测试用例)提交为https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82697

答案 1 :(得分:0)

生成的机器代码无条件地写入两个指针:

do_test:
        cmpl    $1, %edx
        movl    $0x4e931ab1, (%rsi)
        sbbl    %eax, %eax
        andl    $-567890, %eax
        addl    $1234567890, %eax
        movl    %eax, (%rdi)
        ret

这是一个GCC错误,因为所有商店都应该change the dynamic type of the memory accessed。我不认为这种行为是标准规定的;这是GCC的延伸。

你能提交GCC错误吗?