简体   繁体   English

C中的严格别名规则

[英]Strict aliasing rule in C

I'm trying to understand strict aliasing rule as defined in 6.5(p6) : 我正在尝试理解6.5(p6)定义的严格别名规则:

If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. 如果通过具有非字符类型的左值的值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值。

and 6.5(p7) : 6.5(p7)

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88) 对象的存储值只能由具有以下类型之一的左值表达式访问:88)

— a type compatible the effective type of the object - 兼容对象的有效类型的类型

Consider the following example: 请考虑以下示例:

struct test_internal_struct_t{
    int a;
    int b;
};

struct test_struct_t{
    struct test_internal_struct_t tis;
};

int main(){
    //alocated object, no declared type
    struct test_struct_t *test_struct_ptr = malloc(sizeof(*test_struct_ptr)); 

    //object designated by the lvalue has type int
    test_struct_ptr->tis.a = 1; 

    //object designated by the lvalue has type int
    test_struct_ptr->tis.b = 2; 

    //VIOLATION OF STRICT ALIASING RULE???
    struct test_internal_struct_t tis = test_struct_ptr->tis; 
    return 0;
}

The malloc(sizeof(*test_struct_ptr)) has no declared type, since it is allocated, as footnote 87: malloc(sizeof(*test_struct_ptr))没有声明的类型,因为它被分配,如脚注87所示:

87) Allocated objects have no declared type 87)分配的对象没有声明的类型

The objects accessing via test_struct_ptr->tis.a and test_struct_ptr->tis.b has effective type to be int . 通过test_struct_ptr->tis.atest_struct_ptr->tis.b访问的对象的有效类型int But the object test_struct_ptr->tis has no effective type since it is allocated. 但是对象test_struct_ptr->tis没有有效的类型,因为它被分配了。

QUESTION: Is struct test_internal_struct_t tis = test_struct_ptr->tis; 问题: struct test_internal_struct_t tis = test_struct_ptr->tis; a violation of strict aliasing? 违反严格的别名? Object designated by test_struct_ptr->tis has no effective type, but lvalue has type struct test_internal_struct_t . test_struct_ptr->tis指定的对象没有有效类型,但是lvalue类型为struct test_internal_struct_t

C 2018 6.5 6 defines effective type using the phrase “stored … through an lvalue” but never defines that phrase: C 2018 6.5 6使用短语“存储...通过左值”定义有效类型 ,但从不定义该短语:

If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value. 如果通过具有非字符类型的左值的值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值。

So it is left to readers to interpret. 因此,读者需要解释。 Consider this code: 考虑以下代码:

struct a { int x; };
struct b { int x; };

void copy(int N, struct a *A, struct b *B)
{
    for (int n = 0; n < N; ++n)
        A[n].x = B[n].x;
}

If the compiler knows that the various objects A[n] do not overlap the various objects B[n] , then it can optimize this code by performing a load of several B[n] in one instruction (such as an AVX or other single-instruction multiple-data [SIMD] instruction) and storing several A[n] in one instruction. 如果编译器知道各种对象A[n]不与各种对象B[n]重叠,那么它可以通过在一条指令(例如AVX或其他单指令B[n]中执行多个B[n]的加载来优化该代码。 - 指令多数据[SIMD]指令)并在一条指令中存储多个A[n] (This may require additional code to handle loop fragment and alignment issues. Those do not concern us here.) If it is possible that some A[n]->x might refer to the same object as a B[n]->x for a different value of n , then the compiler may not use such multi-element loads and stores, as it could change the observable behavior of the program. (这可能需要额外的代码来处理循环片段和对齐问题。这些与我们无关。)如果有可能某些A[n]->x可能引用与B[n]->x相同的对象对于不同的n值,编译器可能不会使用这样的多元素加载和存储,因为它可能会改变程序的可观察行为。 For example, if the situation were that memory contained ten int with values from 0 to 9 and B pointed to the 0 while A pointed to the 2: 例如,如果情况是内存包含10个int ,值为0到9, B指向0,而A指向2:

B   A
0 1 2 3 4 5 6 7 8 9

Then the loop as written, given N = 4, must copy the elements one at a time, producing: 然后在给定N = 4的情况下写入的循环必须一次复制一个元素,产生:

0 1 0 1 0 1 6 7 8 9

If the compiler optimized this to four-element loads and stores, it could load 0 1 2 3 and then store 0 1 2 3, producing: 如果编译器将此优化为四元素加载和存储,则可以加载0 1 2 3然后存储0 1 2 3,从而产生:

0 1 0 1 2 3 6 7 8 9

However, C tells us that struct a and struct b are incompatible, even though they are laid out identically. 但是,C告诉我们struct astruct b是不兼容的,即使它们的布局相同。 When types X and Y are incompatible, it tells us that an X is not a Y . 当类型XY不兼容时,它告诉我们X不是Y A significant purpose of the type system is to distinguish object types. 类型系统的一个重要目的是区分对象类型。

Now consider the expression A[n]->x = B[n]->x . 现在考虑表达式A[n]->x = B[n]->x In this: 在这:

  • A[n] is an lvalue for a struct a . A[n]struct a的左值。
  • Since A[n] is the left operand of a . 由于A[n]是a的左操作数. , it is not converted to a value. ,它不会转换为值。
  • A[n].x designates and is an lvalue for the member x of A[n] . A[n].x表示并且是A[n]的成员x的左值。
  • The value of the right operand replaces the value in A[n].x . 右操作数的值替换A[n].x的值。

So, the direct access to an object that stores a value is solely in the int that is the member A[n].x . 因此,对存储值的对象的直接访问仅在作为成员A[n].xint中。 The lvalue A[n] appears in the expression, but it is not the lvalue used directly to store a value. 左值A[n]出现在表达式中,但它不是直接用于存储值的左值。 What is the effective type of the memory at &A[n] ? &A[n]的内存有效类型是什么?

If we interpret this memory as merely an int , then the only restriction on the object accesses is that all the B[n].x are int and all the A[n].x are int , so some or all of the A[n].x may access the same memory as some or all of the B[n].x , and the compiler is not permitted to make the optimization described above. 如果我们将这个内存解释为只是一个int ,那么对象访问的唯一限制是所有B[n].x都是int而且所有A[n].x都是int ,所以A[n].x部分或全部A[n].x可以访问与B[n].x一些或全部相同的存储器,并且不允许编译器进行上述优化。

This does not serve the purpose of the type system to distinguish struct a and struct b , and so it cannot be a correct interpretation. 这不符合类型系统的目的,以区分struct astruct b ,因此它不能是正确的解释。 To enable the intended optimization, it must be that the memory stored by A[n].x contains struct a objects, and the memory accessed by B[n].x contains struct b objects. 要启用预期的优化,必须是A[n].x存储的内存包含struct a对象,而B[n].x访问的内存包含struct b对象。

Therefore, “stored … through an lvalue” must include expressions where an lvalue is used to derive members of structures but is not itself the final lvalue used for access. 因此,“通过左值存储”必须包括表达式,其中左值用于派生结构成员,但本身不是用于访问的最终左值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM