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

有没有一种方法可以确定指针的表示在C中是否是“线性的”?

  •  3
  • CPlus  · 技术社区  · 1 年前

    据我所知,在C中,如果指针转换为整数,则无法保证指针算术的行为反映整数算术的行为。换句话说,不能保证以下任何断言都成立:

    char a[2]; // So that p + 1 is a valid memory location
    char *p = a;
    assert(p + 1 == (char *)((uintptr_t)p + 1));
    
    int x;
    int *p = &x;
    assert((intptr_t)p % sizeof(int) == 0);
    

    在大多数系统中,这些都会成立。指针整数表示的尾随位将表示指针对齐,向指针添加某个偏移量与向指针的整数表示添加偏移量乘以指针类型的大小相同。

    然而,是否有任何方法可以确定,理想情况下是在编译时,在任何特定的实现上,这些假设是否始终适用于 任何 指针,前提是指针算法无论如何都会产生一个有效的指针,因为标准不保证它们?例如,在不受支持的实现上早期失败,在替代实现上回退等。

    2 回复  |  直到 1 年前
        1
  •  3
  •   Eric Postpischil    1 年前

    根据评论中的讨论,问题是C标准的规范是否提供了一种可靠的方法来确定断言在任何特定的C实现中是否成立。(因此,问题不在于C实现是否可以提供某种方式来了解这一点,比如通过预定义程序可以测试的预处理器宏。问题在于是否有一种测试在所有C实现中都有效。)

    答案是否定的。

    由于这个答案依赖于C标准中没有这方面的事实,因此除了参考整个C标准外,没有其他方法可以证明这一点。我对当前的C标准相当熟悉,并认为它没有提供任何这样的机制。

    注释69至C 2018 6.3.2.2 5告诉我们,将指针转换为整数或将整数转换为指针的映射函数旨在与执行环境的寻址结构保持一致,但这不是标准的规范部分,我相信标准中没有规定任何关于此映射的信息应由C实现提供。指针和整数映射也没有任何规定的属性来测试断言是否始终成立。

        2
  •  1
  •   Petr Skocik    1 年前

    你真的不能在整数常量表达式中进行指针运算。因此,我认为正确编译测试的唯一方法是创建另一个程序并输出一个预处理器常量,您可以在该常量上执行以下操作 #if .

    然而,这可能不是必要的。一个事实上的compiletime表达式可能会这样做。在gcc和clang上都有一个测试,例如:

    char a[2];
    if (a + 1 != (char *)((uintptr_t)a + 1)) abort();
    

    已优化(不与clang一起使用 char *p = a; 赋值),即如果将测试视为事实上的编译时间常数( https://godbolt.org/z/z85a9W3E8 ). 依靠这种优化可能对你来说就足够了。

    要测试任何指针,您应该测试允许具有不同表示的指针类型。本机指针类型可以。结构/联合指针不能。 或者,不要测试和声明不值得支持的平台。