C++ 存储无效指针是否会自动取消定义行为?

C++ 存储无效指针是否会自动取消定义行为?,c++,c,pointers,C++,C,Pointers,显然,取消引用无效指针会导致未定义的行为。但是,简单地在指针变量中存储一个无效的内存地址怎么样 考虑以下代码: const char* str = "abcdef"; const char* begin = str; if (begin - 1 < str) { /* ... do something ... */ } const char*str=“abcdef”; const char*begin=str; 如果(begin-1 < P>任何使用无效指针的行为都会产生未定义的行为。我

显然,取消引用无效指针会导致未定义的行为。但是,简单地在指针变量中存储一个无效的内存地址怎么样

考虑以下代码:

const char* str = "abcdef";
const char* begin = str;
if (begin - 1 < str) { /* ... do something ... */ }
const char*str=“abcdef”;
const char*begin=str;
如果(begin-1
表达式
begin-1
的计算结果是无效的内存地址。请注意,我们实际上并没有取消引用这个地址——我们只是在指针算法中使用它来测试它是否有效。尽管如此,我们仍然必须将无效的内存地址加载到寄存器中


那么,这是未定义的行为吗?我从来没想过会是这样,因为很多指针运算似乎都依赖于这类东西,而指针实际上就是一个整数。但最近我听说,即使是将无效指针加载到寄存器中的行为也是未定义的行为,因为如果这样做,某些体系结构会自动抛出总线错误或其他错误。有人能指出C或C++标准的相关部分,这两种方法都能解决吗?< /P> < P>任何使用无效指针的行为都会产生未定义的行为。我这里没有C标准,但请参见基本原理中的“无效指针:

我这里有C草案标准,它通过省略使其未定义。它在第6.5.6/8节中定义了
ptr+I
的情况

  • 如果指针操作数指向数组对象的某个元素,且数组足够大,则结果将指向与原始元素偏移的元素,从而使结果数组元素和原始数组元素的下标之差等于整数表达式
  • 此外,如果表达式P指向数组对象的最后一个元素,表达式(P)+1指向数组对象的最后一个元素,如果表达式Q指向数组对象的最后一个元素,则表达式(Q)-1指向数组对象的最后一个元素

你的箱子一个都不适合。数组的大小既不足以使
-1
调整指针以指向其他数组元素,也不足以使任何结果或原始指针指向另一端

您的代码是未定义的行为,原因不同:

表达式
begin-1
不会产生无效指针。这是未定义的行为。不允许执行超出正在处理的数组边界的指针算术运算。因此,减法本身是无效的,而不是存储结果指针的行为

$5.7/6-“除非两个指针都指向 对于同一数组对象的元素, 或者是一个超过最后一个元素的 数组对象,其行为为 未定义。75“


总之,它是未定义的,即使您没有取消引用指针

是的,它是未定义的行为。注意。将无效指针分配给变量、比较无效指针、强制转换无效指针会触发未定义的行为。

某些体系结构具有用于保存指针的专用寄存器。将未映射地址的值放入这样的寄存器会导致崩溃。允许整数溢出/下溢崩溃。因为C的目标是在各种各样的平台上工作,指针提供了一种安全编程不安全电路的机制

如果您知道您不会在具有如此挑剔特性的外来硬件上运行,那么您就不必担心语言未定义的内容。它由平台定义良好


当然,这个例子的风格很差,没有很好的理由这样做。

正确的答案多年前就已经给出了,但我发现有趣的是,[sec.6.5.6,最后3段]解释了为什么标准支持将
1
添加到指向数组最后一个元素的指针(
p+1
):

普遍做法的一个重要认可是,指针始终可以递增到刚好超过数组末尾,而不必担心溢出或换行

为什么
p-1
不被认可:

另一方面,在p-1的情况下,必须在p遍历的对象数组之前分配整个对象,因此从数组底部运行的递减循环可能会失败。例如,这种限制允许分段体系结构将对象放置在一系列可寻址内存的开头

因此,如果指针
p
指向可寻址内存范围开始处的一个对象,该范围由该注释支持,那么
p-1
将产生下溢

请注意,整数溢出是标准中未定义行为的示例【第3.4.3节】,因为它取决于翻译环境和操作环境。我相信很容易看出这种对环境的依赖扩展到了指针下溢

这就是为什么该标准明确规定了未定义的行为[在6.5.6/8中],如其他答案所述。引用这句话:

如果指针操作数和结果都指向同一数组对象的元素,或超过数组对象最后一个元素的元素,则计算不应产生溢出;否则,行为是未定义的


另请参见C99原理的[第6.3.2.3节,最后4段],其中对无效指针的生成方式以及可能产生的影响进行了更详细的描述。

如果是这样,在执行指针算术时,您不能将所有指针都转换为
ptrdiff\t
?换句话说,如果我将上面的代码示例更改为
if((ptrdiff_t)begin-1)
这是否不再是未定义的行为?不是未定义的行为,但结果是实现定义的。也就是说,您的实现将记录一些合理的行为,但它不会是可移植的,也可能没有用处