为什么这种隐式转换(在不同的指针类型之间)有效?

Nik*_*iou 13 c pointers implicit-conversion

我发现自己处于以下情况:

#include <stdio.h>

typedef struct T1 { int id; } T1;  
typedef struct T2 { int id; } T2;

void f(T1 *ptr) { printf("f called\n"); }

int main(void) 
{
    T2 obj; 
    T2 *ptr = &obj; 
    f(ptr); // shouldn't this be a compilation error ? 
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当然,这是无效的C++,但在C中,程序打印 "f called".这有效吗?

编辑

(以防万一不清楚)如果"结构上"不同,程序仍然可以编译和运行T2,例如

typedef struct T2 { double cc[23]; } T2;
Run Code Online (Sandbox Code Playgroud)

Sha*_*our 11

这是无效的,如果要强制使用符合标准的代码,则使用正确的标志进行编译非常重要,例如以下标志gccclang以下标志:

-std=c99 -pedantic-errors
Run Code Online (Sandbox Code Playgroud)

将为C99标准所需的诊断生成错误,同样可以-std=c11用于C11.这将产生以下错误gcc(参见实时):

错误:从不兼容的指针类型传递'f'的参数1

编译器具有扩展并允许由遗留代码引起的隐式int等功能,因此了解差异非常重要.有关详细信息,请参阅gcc文档:GCC支持的语言标准.

快速查看这实际上无效的方法是转到国际标准编程语言的基本原理-C,它在6.3.2.3 指针处理转换时告诉我们:

将指向任何类型的对象的指针转换为指向不同类型的对象的指针而无需显式强制转换是无效的.

稍微长一点的路径要求我们进入C99标准部分草案中的6.5.2.2 函数调用(强调我的前进):

如果表示被调用函数的表达式具有包含原型的类型,则隐式转换参数,就像通过赋值一样,

然后,如果我们转到6.5.16 分配运算符部分,它说:

以下之一应持有

我们有指针:

  • 两个操作数都是指向兼容类型的限定或非限定版本的指针,左边指向的类型具有右边指向的所有类型的限定符;
  • 一个操作数是指向对象或不完整类型的指针,另一个是指向void的限定或非限定版本的指针,左边指向的类型具有右边指向的所有类型的限定符;
  • 左操作数是一个指针,右边是一个空指针常量;

我们发现这些情况都不成立,因此转换无效.


slu*_*ion 6

编译时,我收到以下警告:

temp.c:在函数'main'中:

temp.c:20:5:警告:从不兼容的指针类型[默认启用]传递'f'的参数1

temp.c:13:6:注意:预期'struct T1*'但参数类型为'struct T2*'

它是"有效的",因为它们都是指针,因此可以转换,这不是一个好主意.

  • 请看我的回答,这是无效的. (2认同)