C指针:来自不兼容指针类型的分配

时间:2019-03-18 21:45:48

标签: c pointers gcc gcc-warning

当我使用gcc 7.3.0编译此代码时,我收到“来自不兼容指针类型的赋值”。

int intVar = 1;
char* charPointer;

charPointer = &intVar;
printf("%d", *charPointer);

到目前为止,一切都很好。我可以这样处理指针:

charPointer = (char*)&intVar;

现在我的疑问是:第二种情况有何不同?如果我不将charPointer强制转换为int *,例如将其递增n或取消引用,我仍然会搞砸。那么,为什么在这两种情况下编译器的行为有所不同?他为什么要关心分配过程中指针类型是否不匹配?我只想了解其背后的逻辑。

3 个答案:

答案 0 :(得分:1)

指针转换有点危险。

如果转换所依据的指针类型与目标类型的对齐方式不足,则会在转换时得到UB(==未定义的行为;请仔细阅读其含义,除非您已经知道)。

否则,如果由于C的strict aliasing rules要求您通过与有效类型充分兼容的左值类型访问对象,则通常在取消引用时得到UB。

尽管上一段不适用于char指针的转换,因为char指针可以别名任何类型,但警告(编译器也可能使它成为硬错误)仍然有用,因为转换仍然很危险。 / p>

printf("%d", *(char*)&(int){0xFFFF});

将仅使您获得第一个字节(取决于字节序,字节是最高位还是最低位),输出255(如果实现的char类型是无符号的)或-1(如果它是实现的)已签名)。

printf("%d", *&(int){0xFFFF});

将为您获取int中的所有字节。

如果编译器仅警告您就可以从char *分配给int *,则其行为应与强制类型转换相同,但是您需要强制类型转换才能使C保持一致(并使编译器对转换保持沉默)。

答案 1 :(得分:1)

由于临时类型从int *更改为char *,因此编译器警告潜在的陷阱。通过强制转换,编译器假定编码人员知道他们在做什么。


在C语言中,各种类型的指针可以位于不同的地方,具有不同的大小,并且编码方式也不同。

所有对象指针int*char *struct foo *)共享相同的大小和编码是很常见的,但是通常,不需要。

In与对象指针的大小不同时,函数指针的大小并不罕见。

char *void *共享相同的大小,并且编码和字符指针指向具有最小对齐要求的数据。将非char*对象指针转换为char *总是“有效”。并非总是如此。导致不确定的行为(UB)。

转换为非字符指针也有抗锯齿的风险(编译器需要跟踪通过一种指针类型反映的数据更改反映在另一种指针类型上)。可能会产生非常奇怪的未定义行为。> 更好的代码避免了指针类型的更改 1 ,并且在需要时通过强制转换是显式的。


1 例外,包括在不考虑对齐问题时将对象指针更改为void *或将格式为void*的情况。

答案 2 :(得分:0)

正如@Mike Holt所说的,实际上并没有什么不同,只是您告诉编译器“不用担心,我的意思是这样做”。

编译器确实会担心,因为分配给其他类型的指针通常不是您想要执行的操作。您的代码告诉编译器“处理包含此变量的内存,就好像它持有其他类型的变量一样”。几乎可以肯定,这是平台特定的行为,可能是未定义的行为,具体取决于类型。

相关问题