此代码是否违反了严格的别名规则?

hyd*_*yde 15 c strict-aliasing language-lawyer

问题:

  1. 下面的代码是否违反了严格的别名规则?也就是说,是否允许智能编译器打印00000(或其他一些令人讨厌的效果),因为然后通过int*?访问首先作为其他类型访问的缓冲区?

  2. 如果没有,那么只会移动ptr2大括号之前的定义和初始化(因此ptr2将在定义ptr1范围时定义)打破它吗?

  3. 如果没有,将删除大括号(因此ptr1,ptr2并在同一范围内)打破它?

  4. 如果是,代码如何修复?

额外的问题:如果代码没问题,并且2.或3.也不要破坏它,如何更改它以便打破严格的别名规则(例如,转换支撑循环使用int16_t)?


int i;
void *buf = calloc(5, sizeof(int)); // buf initialized to 0

{
    char *ptr1 = buf;    
    for(i = 0; i < 5*sizeof(int); ++i)
        ptr1[i] = i;
}

int *ptr2 = buf;
for(i = 0; i < 5; ++i)
    printf("%d", ptr2[i]);
Run Code Online (Sandbox Code Playgroud)

寻找确认,如此简短(ish),关于这个特定代码的专家答案,理想情况下用最小的标准报价,就是我所追求的.我不是经过长时间的严格别名规则解释,只是与此代码相关的部分.如果答案明确列举上面的编号问题,那将是很好的.

还假设没有整数陷阱值的通用CPU,也可以说int是32位和2位补码.

250*_*501 13

不,它不是,但这只是因为内存被分配,并使用字符类型写入.

内存使用malloc分配.该对象没有声明1类型,因为它是使用malloc分配的.因此,该对象没有任何有效类型.

然后代码使用类型访问和修改对象char.由于类型为2 char且没有复制具有有效类型的对象5,因此复制不会char为此次访问和后续访问设置有效类型,而是将有效类型设置为char仅在访问3的持续时间内.访问后,对象不再具有有效类型.

然后,该类型int用于访问并仅读取该对象.由于对象没有有效类型,因此在读取期间它变为3 int.访问后,对象不再具有有效类型.由于int显然与有效类型兼容,因此int定义了行为.

(假设读取的值不是陷阱表示int.)


如果您使用与其不兼容的非字符类型访问和修改对象int,则行为将是未定义的.

假设你的例子是(假设sizeof(float)==sizeof(int)):

int i;
void *buf = calloc(5, sizeof(float)); // buf initialized to 0

{
    float *ptr1 = buf;    
    for(i = 0; i < 5*sizeof(float); ++i)
        ptr1[i] = (float)i;
}

int *ptr2 = buf;
for(i = 0; i < 5; ++i)
    printf("%d", ptr2[i]);
Run Code Online (Sandbox Code Playgroud)

float写入s 时,对象的有效类型在写入float期间以及对不修改它的对象的所有后续访问中变为类型2.然后,int当有效类型仍然访问这些对象时float,因为只读取值而不进行修改.先前的写入使用float将有效类型设置为float永久有效,直到下一次写入此对象(在这种情况下不会发生).类型intfloat不兼容4,因此行为是不确定的.


(以下所有文字均引自:ISO:IEC 9899:201x)

1(6.5表达式6)
访问其存储值的对象的有效类型是对象的声明类型(如果有).87)分配的对象没有声明的类型.

2(6.5表达式6)
如果通过具有非字符类型的左值的值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型不修改存储值的访问.

3(6.5表达式6)
对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型.

4(6.5表达式8)
对象的存储值只能由具有以下类型之一的左值表达式访问:88) - 与对象的有效类型兼容的类型, - 与之兼容的类型的限定版本对象的有效类型, - 对应于对象的有效类型的有符号或无符号类型的类型, - 对应于对象的有效类型的限定版本的有符号或无符号类型, - 聚合或联合类型,包括其成员中的上述类型之一(包括递归地,子聚合或包含联合的成员),或 - 字符类型.

5(6.5表达式6)
如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及后续访问的有效类型不修改值是从中复制值的对象的有效类型(如果有).

  • @AndrewHenle我认为"复制为一个字符类型数组"意味着暗示一个值从另一个对象复制*整个*,这不是这里的情况(int值是通过字符指针存储的,但是表示不复制).不幸的是,标准中没有明确定义(许多失败之一). (2认同)