無法通過非字元型別訪問字元型別
如果使用靜態,執行緒或自動儲存持續時間定義物件,並且它具有字元型別:char
,unsigned char
或 signed char
,則可能無法通過非字元型別訪問它。在下面的示例中,char
陣列被重新解釋為 int
型別,並且在 int
指標 b
的每次取消引用時行為都是未定義的。
int main( void )
{
char a[100];
int* b = ( int* )&a;
*b = 1;
static char c[100];
b = ( int* )&c;
*b = 2;
_Thread_local char d[100];
b = ( int* )&d;
*b = 3;
}
這是未定義的,因為它違反了有效型別規則,沒有具有有效型別的資料物件可以通過另一種非字元型別的型別訪問。由於此處的其他型別是 int
,因此不允許這樣做。
即使已知對齊和指標大小適合,這也不會免除此規則,行為仍然是未定義的。
這尤其意味著在標準 C 中沒有辦法保留可以通過不同型別的指標使用的字元型別的緩衝區物件,因為你將使用 malloc
或類似函式接收的緩衝區。
實現與上述示例相同目標的正確方法是使用 union
。
typedef union bufType bufType;
union bufType {
char c[sizeof(int[25])];
int i[25];
};
int main( void )
{
bufType a = { .c = { 0 } }; // reserve a buffer and initialize
int* b = a.i; // no cast necessary
*b = 1;
static bufType a = { .c = { 0 } };
int* b = a.i;
*b = 2;
_Thread_local bufType a = { .c = { 0 } };
int* b = a.i;
*b = 3;
}
這裡,union
確保編譯器從一開始就知道可以通過不同的檢視訪問緩衝區。這也具有以下優點:現在緩衝區具有檢視a.i
,其已經是 int
型別並且不需要指標轉換。