C/C++ 不确定值:编译器优化提供不同的输出(示例)
C/C++ Indeterminate Values: Compiler optimization gives different output (example)
似乎C/C++编译器(clang,gcc等)产生与优化级别相关的不同输出。您也可以查看本文中包含的在线链接。
http://cpp.sh/5vrmv(将输出从 none 更改为 -O3 以查看差异)。
根据以下一段代码,有人可以解释我的几个问题:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = (int *)malloc(sizeof(int));
free(p);
int *q = (int *)malloc(sizeof(int));
if (p == q) {
*p = 10;
*q = 14;
printf("%d", *p);
}
return 0;
}
- 确定执行将始终进入 if 语句吗?我们怎么知道两个指针 p 和 q 的地址会相同?
- 为什么 no-optimization 的输出为 14,而 -O3 的输出为 10 ?
free(p);
这会将p
的内容转换为无效的指针值。
int *q = (int *)malloc(sizeof(int));
这条线与p
无关。
if (p == q) {
这是实现定义的行为,因为p
具有无效的指针值。
*p = 10;
最后,这是未定义的行为,原因与上述相同。
C++标准 §3.7.4.2/4:
如果参数给出给标准中的释放函数 库是一个不是空指针值 (4.10) 的指针,即 释放函数应释放 指针,使引用 已解除分配的存储。通过无效指针值和 将无效的指针值传递给释放函数具有 未定义的行为。无效指针值的任何其他用法都有 实现定义的行为。
因此,您的问题的答案是:
确定执行将始终进入 if 语句吗?
这取决于实现。C++语言不能保证这一点。
为什么 no-optimization 的输出为 14,而 -O3 的输出为 10
?
因为当您取消引用无效指针时,行为是未定义的。
在C中,比较本身是未定义的行为。C 标准中的附录 J.2 列出了行为未定义的情况,该列表包括:
使用指向生存期已结束的对象的指针的值。
您可能会发现以下问题(包括所有评论和答案)很有趣:未定义、未指定和实现定义的行为
确定执行将始终进入 if 语句吗?我们怎么知道两个指针 p 和 q 的地址会相同?
这是实现定义的,您不能依赖此行为。 p
和q
确实可以相等,您已经释放了p
指向的内存,因此q
可能会获得与p
相同的地址。
为什么 no-optimization 的输出为 14,而 -O3 的输出为 10
?
这就是优化器的工作方式,您可以在此处查看您的版本:
https://goo.gl/yRfjIv
其中编译器优化了 14 的赋值,而这里的版本看起来是正确的:
https://goo.gl/vSVV0E
正在分配值 14,我只添加了一行p = q;
我不确定为什么它会这样工作,我会说编译器假设您的代码没有未定义的行为代码,并在这种假设下进行优化。
[编辑]
未定义的行为是由编译器假定不再有效的指针值的使用引起的,它是否稍后等于某些新分配的内存块并不重要。适当的标准报价由TartanLlama给出:
[基本.stc.dynamic.safety]
[ 注意:使用无效指针值的效果(包括将其传递给 释放函数)未定义,请参见 3.7.4.2。即使不安全派生的指针值可能 等于某些安全派生的指针值。—尾注 ]
if
-条件可能是假的 - 根据malloc()
的特定实现,它可能会返回刚刚释放的块以供重用或另一个块。
但是,如果程序打印任何内容(因为碰巧q
等于 p
),它必须打印14
。产生其他任何东西的编译器都是有缺陷的......
3.6.2,我始终得到正确的答案,而 gcc 4.2.1 和 5.3.0 都表现出该错误。不幸的是,clang 3.8.0也是如此。
- 激励'inline'说明符的真实世界示例?
- 递归函数计算序列中的平方和(并输出过程)
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 请解释"函数1(p1,p2,p3);"的输出
- C++:将控制台输出存储在宏中更好吗
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 为什么我的代码在输出中增加了93天
- 如何从void函数输出字符串
- 输入到文件并输出到另一个文件,并将流文件传递给函数
- 使用 python 或 c ++ 中的 sql 根据输入数据输出输出示例
- 执行输出模式必须与示例相同
- qt音频输出示例未构建--缺少生成器类声明
- Doxygen@param direction arguments[in],[out],[in,out]示例输出
- 维基百科输入/输出示例上的拼写错误
- C/C++ 不确定值:编译器优化提供不同的输出(示例)
- 使用输出迭代器不起作用的通用函数示例
- 我真的需要通过查看主程序和示例执行输出来理解如何编写类(声明和定义)
- 使用 openCV c++ 示例代码执行抓取后保存输出图像
- Boost图形库-顶点颜色和graphviz输出的最小示例