无法通过非字符类型访问字符类型

如果使用静态,线程或自动存储持续时间定义对象,并且它具有字符类型:charunsigned charsigned 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 类型并且不需要指针转换。