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

C 两个实现定义的相同表达式能否给出不同的结果?,c,language-lawyer,C,Language Lawyer,有关: 让我们考虑一下: 案例1: uintpttr_tNULL-uintpttr_tNULL结果是否始终为零 案例2由Eric评论引发: x-x永远是零吗 案例3: x-y总是零吗 案例4: x-y总是零吗 如果没有-为什么?您将找不到一个在任何地方使用的系统,其中NULL未定义为0的某种形式,无论是文字值还是值为0的void*,因此所有检查都将按照预期工作,或者语法错误无法减去void*值 但是,它是否可以被定义为其他任何东西?理论上。虽然它仍然是一个常数,所以减去它们,语言和类型允许值仍然

有关:

让我们考虑一下:

案例1: uintpttr_tNULL-uintpttr_tNULL结果是否始终为零

案例2由Eric评论引发:

x-x永远是零吗

案例3: x-y总是零吗

案例4: x-y总是零吗


如果没有-为什么?

您将找不到一个在任何地方使用的系统,其中NULL未定义为0的某种形式,无论是文字值还是值为0的void*,因此所有检查都将按照预期工作,或者语法错误无法减去void*值

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

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

对。它是实现定义的-所有规则都取决于实现。想象的实现可能如下所示:

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开关来选择用于取消引用指针的库

uintpttr_tNULL-uintpttr_tNULL结果是否始终为零? 不一定

x-x永远是零吗? 对。uintptr_t是一种无符号整数类型,它必须遵守数学定律

x-y总是零吗? 不一定

x-y总是零吗? 不一定

如果没有,为什么

从void*到uintpttr__t的转换结果由实现定义-实现每次可能将指针值转换为不同的uintpttr_t值,这将导致值之间的差异非零


我可以看到一个例子:在一些假想的体系结构上,指针有48位,而uintptru\t有64位。这种体系结构的编译器根本不关心这16个额外位中的内容,在将uintptr\t转换为指针时,它只使用48位。当将指针转换为uintrpt时,编译器会使用寄存器中剩余的任何垃圾值作为额外的16位,因为在特定的体系结构中,这样做很快,而且在转换回uintrpt时,它们永远不会被使用。

您是从理论上还是从实践上问这个问题?因为我可以编写一个编译器,并记录在我的自定义编译器中,表达式NULL-NULL等于0,除非在第12行,否则它等于62,并且它仍然是实现定义的。如果这样的编译器仍然可以达到程序的一致性行为,即,它将跟踪指针值中哪一行上转换了哪些指针,那么就可以了。@KamilCuk做吧!:D@KamilCuk你知道语言律师标签是什么意思吗?IntuitPtr\t不是我要问的。pragma MYCOMPILER SHIFT\u uintpttr 5 printf%d\n,IntuitPtr\u ta;//prints 5和pragma MYCOMPILER SHIFT\u uintpttr 0 printf%d\n,intuintptr\u ta;//打印0是两个不同的表达式。它们不一样。我不是在问关于实现的问题。问题是关于C标准。阅读标记如果NULL未定义为某种形式的0 ny\u killer\u编译器:define NULL-1,则在任何地方都找不到正在使用的系统。现在你有一个implementation@P__JsupportswomeninPoland定义NULL-1。现在您有了一个不符合要求的实现。如果NULL未定义为0的某种形式,您将找不到正在使用的系统。现在可能没有,但是你看到线了吗?它不符合当前的标准,这些标准要求在转换为整数类型时,null指针产生零。但是,后者仅适用于整数转换,空指针的内部表示形式不必仅为零字节。
uintptr_t x = (uintptr_t)NULL, y = (uintptr_t)NULL;
void *a; 

/* .... */

uintptr_t x = (uintptr_t)a, y = (uintptr_t)a;
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
}