代码之家  ›  专栏  ›  技术社区  ›  Amine

你能互相分配不同类型的指针吗?

  •  0
  • Amine  · 技术社区  · 6 年前

    考虑到

    T1 *p1;
    T2 *p2;
    

    我们能把p1分配给p2吗?反之亦然?如果是这样的话,我们可以不用石膏板还是必须用石膏板?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Steve Summit    6 年前

    当类型 T1 T2 T1 *p1 T2 *p2 除非至少有一个 T1级 T2级 void

    在许多情况下,不兼容的赋值在实践中会起作用,特别是在具有“扁平”地址空间且所有指针类型共享相同内部表示形式的计算机上(例如今天所有流行的计算机)。

    然而,在“混合模式”指针赋值之后,由于(1)对齐问题和(2)原因,在取消引用指针时很可能会出现问题 strict aliasing .

    由于“混合模式”指针分配在形式上是非法的,而且通常是个坏主意,因此大多数编译器都会对此发出警告。大多数编译器允许使用显式强制转换来抑制警告。大多数时候,演员只是用来压制警告;它不会引入任何实际的转换,这些转换无论如何都不会执行(也就是说,改变 p1 = p2 p1 = (T1 *)p2 很像改变 i = f i = (int)f i 是一个int和 f


    附录:我写道,“当 T1级 T2级 . 例如,类型 char unsigned char 是兼容的,所以这些类型的指针之间的赋值是可以的。有关更多详细信息,请参阅Eric Postdischil的较长答案。

        2
  •  2
  •   Eric Postpischil    6 年前

    首先,让我们考虑不使用强制方式的赋值。C 2018 6.5.16.1 1列出了简单赋值的约束条件,其中一个必须保持。前两个用于算术、结构和联合类型。最后两个处理涉及空指针常量或 _Bool

    • 左操作数具有原子、限定或非限定指针类型,两个操作数都是指向兼容类型的限定或非限定版本的指针,左指的类型具有右指的类型的所有限定符

    • 左操作数具有原子、限定或非限定指针类型,其中一个操作数是指向对象类型的指针,另一个操作数是指向void的限定或非限定版本的指针,左指的类型具有右指的类型的所有限定符

    void * 指向任何对象指针,反之亦然,只要没有限定符( const volatile , restrict ,或 __Atomic

    前者说只要不删除限定符,我们就可以将指针分配给兼容类型。什么是兼容类型?

    6.2.7.1说明:

    • 如果两种类型相同,则它们是兼容的。
    • 其他规则见6.7.2、6.7.3和6.7.6。
    • 如果两个结构、联合或枚举类型在本质上声明相同,则它们在单独的翻译单元中声明是兼容的(有趣的是,在 相同的

    6.7.2.4表示每个枚举类型 enum 类型)与实现定义的选项兼容 char 枚举 可以指定一个指向一个的指针 或者整数类型(反之亦然),但是如果不了解特定的C实现,就无法知道是哪一种类型。

    6.7.3.11表示限定类型必须具有相同的限定符才能兼容。因此 int 与不兼容 const int int * 从被分配到 const int * .

    6.7.6.1 2表示要使两个指针类型兼容,它们必须是指向兼容类型的同一限定指针。例如,这告诉我们 内景* 与不兼容 char * char ** 不能分配给 int ** .

    6.7.6.2 6表示要使两个数组类型兼容,它们必须具有兼容的元素类型,如果它们都具有整数常量大小,则它们必须相同(这允许具有未知大小的数组可以与已知大小的数组兼容。然而,附加的文本指出,如果数组最终具有不同的大小,那么在要求它们兼容的上下文中使用它们将具有未定义的行为。因此,将指针分配给这样的数组可能会满足其约束,并且编译时不会出错,但生成的程序可能会出现错误。)

    6.7.6.3 15为函数类型的兼容性提供了一些复杂的规则。这些规则很复杂,因为函数可以用或不用参数列表、省略号等来声明。我将省略对这些问题的全部讨论。

    这些规则告诉您在没有强制转换的情况下可以进行哪些指针指定。

    • 一个指针可以被转换成具有更多限定符的同一类型,并且结果比较起来与原始类型相同。

    • 习惯于

    • 指向函数类型的指针可以转换为指向另一个函数类型的指针。当转换回时,结果与原始指针进行比较(与对象一样,允许进行此转换,但使用生成的指针调用不兼容的函数具有未定义的行为。)