[英]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.a
和test_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 a
和struct b
是不兼容的,即使它們的布局相同。 當類型X
和Y
不兼容時,它告訴我們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].x
的int
中。 左值A[n]
出現在表達式中,但它不是直接用於存儲值的左值。 &A[n]
的內存有效類型是什么?
如果我們將這個內存解釋為只是一個int
,那么對象訪問的唯一限制是所有B[n].x
都是int
而且所有A[n].x
都是int
,所以A[n].x
部分或全部A[n].x
可以訪問與B[n].x
一些或全部相同的存儲器,並且不允許編譯器進行上述優化。
這不符合類型系統的目的,以區分struct a
和struct b
,因此它不能是正確的解釋。 要啟用預期的優化,必須是A[n].x
存儲的內存包含struct a
對象,而B[n].x
訪問的內存包含struct b
對象。
因此,“通過左值存儲”必須包括表達式,其中左值用於派生結構成員,但本身不是用於訪問的最終左值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.