【问题标题】:Can two implementation defined identical expressions give different results?两个实现定义的相同表达式可以给出不同的结果吗?
【发布时间】:2021-02-20 17:45:41
【问题描述】:

相关:Three questions: Is NULL - NULL defined? Is (uintptr_t)NULL - (uintptr_t)NULL defined?

让我们考虑一下:

  1. 案例 1: (uintptr_t)NULL - (uintptr_t)NULL 结果会一直为零吗?

  2. 案例 2(受 Eric 评论启发):

uintptr_t x = (uintptr_t)NULL;

x - x 会一直为零吗?

  1. 案例 3:
uintptr_t x = (uintptr_t)NULL, y = (uintptr_t)NULL;

x-y 会一直为零吗?

  1. 案例4:
void *a; 

/* .... */

uintptr_t x = (uintptr_t)a, y = (uintptr_t)a;

x-y 会一直为零吗?

如果不是 - 为什么?

【问题讨论】:

  • 你问的是理论还是实践?因为我可以编写一个编译器,并在我的自定义编译器中记录它“表达式 NULL - NULL 等于 0,除非在第 12 行,则它等于 62”,它仍然是“实现定义的”(简直疯了)。如果这样的编译器仍然可以达到程序的一致行为(即,它将跟踪在指针值内的哪一行上转换了哪些指针),那么它可能没问题。
  • @KamilCuk 做吧! :D
  • @KamilCuk 你知道“语言律师”标签是什么意思吗?

标签: c language-lawyer


【解决方案1】:

两个实现定义的相同表达式能否给出不同的结果?

是的。它是“实现定义的”——所有规则都取决于实现。一个虚构的实现可能如下所示:

int main() {
      void *a = 0;
#pragma MYCOMPILER SHIFT_UINTPTR 0
      printf("%d\n", (int)(uintptr_t)a); // prints 0
#pragma MYCOMPILER SHIFT_UINTPTR 5
      printf("%d\n", (int)(uintptr_t)a); // prints 5
}

在大多数平台上,这样的实现仍然是疯狂的。

我可以想象一个例子:必须在“银行”中处理内存的架构。该架构的编译器使用#pragma 开关来选择用于取消引用指针的“银行”。

  1. (uintptr_t)NULL - (uintptr_t)NULL 结果总是为零吗?

不一定。

  1. x - x 会一直为零吗?

是的。 uintptr_t 是无符号整数类型,它必须遵守数学规律。

  1. x-y 总是为零吗?

不一定。

  1. x-y 总是为零吗?

不一定。

如果不是 - 为什么?

void*uintptr_t 的转换结果是实现定义的——实现可能每次都将指针值转换为不同的uintptr_t 值,这将导致值之间存在非零差异。

我可以看到一个例子:在一些虚构的架构上,指针有 48 位,而uintptr_t 有 64 位。这种架构的编译器只是“不在乎”这 16 个额外位中的内容,并且在将 uintptr_t 转换为指针时,它仅使用 48 位。在将指针转换为uintrpt_t 时,编译器使用寄存器中剩余的任何垃圾值来获取额外的 16 位,因为在特定架构中这样做很快,而且在转换回来时永远不会使用它们。..

【讨论】:

  • (int)(uintptr_t) 不是我要问的。#
  • #pragma MYCOMPILER SHIFT_UINTPTR 5 printf("%d\n", (int)(uintptr_t)a); // prints 5#pragma MYCOMPILER SHIFT_UINTPTR 0 printf("%d\n", (int)(uintptr_t)a); // prints 0 是两个不同的表达式。它们不一样。
【解决方案2】:

NULL 未被定义为某种形式的0(无论是文字值还是void * 的值0)的任何地方,您都找不到正在使用的系统,所以您的所有检查要么按您的预期工作,要么出现语法错误(不能减去 void * 值)。

是否有可能被定义为其他任何东西?理论上。虽然它仍然是一个常数,但减去它们(语言和类型允许)仍然等于 0。

【讨论】:

  • 我不是在询问实现。问题是关于C 标准。阅读标签
  • You won't find a system in use anywhere where NULL isn't defined as some form of 0ny_killer_compiller:#define NULL -1。现在你有了一个实现
  • @P__JsupportswomeninPoland #define NULL -1.现在你有了一个不符合要求的实现
  • NULL 未被定义为某种形式的0 的任何地方,您都找不到正在使用的系统。现在可能没有,但您是否看到When was the NULL macro not 0? 线程?它不符合当前标准,要求空指针在转换为整数类型时产生零。但是,后者仅适用于整数 conversion,空指针的内部表示不必仅为零字节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-13
  • 2012-06-22
  • 2018-02-20
  • 2016-04-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多