C 标准中的哪些内容允许编译器将 `(((char *)p - 1) == NULL` 优化为 false?

问题描述 投票:0回答:2

摘取以下片段:

#include <stddef.h>

_Bool
foo(char * p) {
    return (p - 1) == NULL;
}

GCC 和 LLVM 将结果优化为 false

标准中的哪些内容允许编译器假设

p
不是
1

c standards
2个回答
0
投票

这源于两件事:

  • NULL 指针与任何对象或函数指针比较都不相等。
  • 指针算术只能产生指向对象的有效指针(或刚刚经过数组的最后一个元素)。

因此,假设

p
是指向
char
的有效指针,
p - 1
也将是指向
char
的有效指针,并且由于有效指针不能为 NULL,因此在该假设下,比较将始终为 false .


0
投票

在 C 中,定义明确的指针只能指向一个有效对象,或者指向一个有效对象。

当整数类型的表达式与指针相加或相减时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向距原始元素的元素偏移量,使得结果数组元素和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式 P 指向数组对象的第 i 个元素,则表达式 (P)+N (相当于 N+(P))和 (P)-N (其中 N 的值为 n)指向分别为数组对象的第 i+n 个和第 i−n 个元素(前提是它们存在)。此外,如果表达式 P 指向数组对象的最后一个元素,则表达式 (P)+1 指向数组对象的最后一个元素后一位,如果表达式 Q 指向数组对象的最后一个元素后一位,表达式 (Q)-1 指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则求值不会产生溢出;否则,行为是未定义的。如果结果指向数组对象的最后一个元素,则不得将其用作所计算的一元 * 运算符的操作数。

这意味着

p
指向字符数组/结构体等中的有效字符,这不是第一个元素,这意味着在该元素之前,将有一个地址不是
NULL
的有效字符。

或者,您从

char
所在内存块边界之外的有效
char
的地址中减去 1。这会调用未定义的行为,因为减法产生的指针不是数组或指向最后一个元素 1 的指针。

© www.soinside.com 2019 - 2024. All rights reserved.