簡體   English   中英

C中的嚴格別名規則

[英]Strict aliasing rule in C

我正在嘗試理解6.5(p6)定義的嚴格別名規則:

如果通過具有非字符類型的左值的值將值存儲到沒有聲明類型的對象中,則左值的類型將成為該訪問的對象的有效類型以及不修改該值的后續訪問的有效類型儲值。

6.5(p7)

對象的存儲值只能由具有以下類型之一的左值表達式訪問:88)

- 兼容對象的有效類型的類型

請考慮以下示例:

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;
}

malloc(sizeof(*test_struct_ptr))沒有聲明的類型,因為它被分配,如腳注87所示:

87)分配的對象沒有聲明的類型

通過test_struct_ptr->tis.atest_struct_ptr->tis.b訪問的對象的有效類型int 但是對象test_struct_ptr->tis沒有有效的類型,因為它被分配了。

問題: struct test_internal_struct_t tis = test_struct_ptr->tis; 違反嚴格的別名? test_struct_ptr->tis指定的對象沒有有效類型,但是lvalue類型為struct test_internal_struct_t

C 2018 6.5 6使用短語“存儲...通過左值”定義有效類型 ,但從不定義該短語:

如果通過具有非字符類型的左值的值將值存儲到沒有聲明類型的對象中,則左值的類型將成為該訪問的對象的有效類型以及不修改該值的后續訪問的有效類型儲值。

因此,讀者需要解釋。 考慮以下代碼:

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;
}

如果編譯器知道各種對象A[n]不與各種對象B[n]重疊,那么它可以通過在一條指令(例如AVX或其他單指令B[n]中執行多個B[n]的加載來優化該代碼。 - 指令多數據[SIMD]指令)並在一條指令中存儲多個A[n] (這可能需要額外的代碼來處理循環片段和對齊問題。這些與我們無關。)如果有可能某些A[n]->x可能引用與B[n]->x相同的對象對於不同的n值,編譯器可能不會使用這樣的多元素加載和存儲,因為它可能會改變程序的可觀察行為。 例如,如果情況是內存包含10個int ,值為0到9, B指向0,而A指向2:

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

然后在給定N = 4的情況下寫入的循環必須一次復制一個元素,產生:

0 1 0 1 0 1 6 7 8 9

如果編譯器將此優化為四元素加載和存儲,則可以加載0 1 2 3然后存儲0 1 2 3,從而產生:

0 1 0 1 2 3 6 7 8 9

但是,C告訴我們struct astruct b是不兼容的,即使它們的布局相同。 當類型XY不兼容時,它告訴我們X不是Y 類型系統的一個重要目的是區分對象類型。

現在考慮表達式A[n]->x = B[n]->x 在這:

  • A[n]struct a的左值。
  • 由於A[n]是a的左操作數. ,它不會轉換為值。
  • A[n].x表示並且是A[n]的成員x的左值。
  • 右操作數的值替換A[n].x的值。

因此,對存儲值的對象的直接訪問僅在作為成員A[n].xint中。 左值A[n]出現在表達式中,但它不是直接用於存儲值的左值。 &A[n]的內存有效類型是什么?

如果我們將這個內存解釋為只是一個int ,那么對象訪問的唯一限制是所有B[n].x都是int而且所有A[n].x都是int ,所以A[n].x部分或全部A[n].x可以訪問與B[n].x一些或全部相同的存儲器,並且不允許編譯器進行上述優化。

這不符合類型系統的目的,以區分struct astruct b ,因此它不能是正確的解釋。 要啟用預期的優化,必須是A[n].x存儲的內存包含struct a對象,而B[n].x訪問的內存包含struct b對象。

因此,“通過左值存儲”必須包括表達式,其中左值用於派生結構成員,但本身不是用於訪問的最終左值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM