- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
免责声明:以下纯属学术问题;我将此代码与任何生产系统保持至少 100 m 的距离。这里提出的问题是无法在任何“现实生活”案例中衡量的。
考虑以下代码 ( godbolt link ):
#include <stdlib.h>
typedef int (*func_t)(int *ptr); // functions must conform to this interface
extern int uses_the_ptr(int *ptr);
extern int doesnt_use_the_ptr(int *ptr);
int foo() {
// actual selection is complex, there are multiple functions,
// but I know `func` will point to a function that doesn't use the argument
func_t func = doesnt_use_the_ptr;
int *unused_ptr_arg = NULL; // I pay a zeroing (e.g. `xor reg reg`) in every compiler
int *unused_ptr_arg; // UB, gcc zeroes (thanks for saving me from myself, gcc), clang doesn't
int *unused_ptr_arg __attribute__((__unused__)); // Neither zeroing, nor UB, this is what I want
return (*func)(unused_ptr_arg);
}
编译器没有合理的方法知道 unused_ptr_arg
是不需要的(因此归零是浪费时间),但我知道,所以我想通知编译器 unused_ptr_arg
可以有任何值,例如寄存器中用于将其传递给 func
的任何值。
有没有办法做到这一点?我知道我超出了标准,所以我可以接受特定于编译器的扩展(尤其是 gcc 和 clang)。
最佳答案
在 GCC 和 Clang 以及其他支持 GCC 扩展汇编语法的编译器中,您可以这样做:
int *unused_ptr_arg;
__asm__("" : "=x" (unused_ptr_arg));
return (*func)(unused_ptr_arg);
__asm__
构造 says “这里是一些汇编代码,此时要插入到程序中。它会将结果写入 unused_ptr_arg
中您选择的任何位置。” (x
约束意味着编译器可以选择内存、处理器寄存器或机器支持的任何其他内容。)但实际的汇编代码是空的 (""
)。所以没有生成汇编代码,但是编译器认为unused_ptr_arg
已经被初始化了。在用于 x86-64 的 Clang 6.0.0 和 GCC 7.3(目前在 Compiler Explorer 中的最新版本)中,这会生成一个没有 xor
的 jmp
。
考虑一下:
int *unused_ptr_arg;
(void) &unused_ptr_arg;
return (*func)(unused_ptr_arg);
(void) &unused_ptr_arg;
的目的是获取 unused_ptr_arg
的地址,即使该地址未被使用。这将禁用 C 2011 [N1570] 6.3.2.1 2 中的规则,该规则表示如果程序使用本可以通过 register
声明的具有自动存储持续时间的未初始化对象的值,则行为未定义。因为它的地址被占用了,它不能用register
声明,因此根据这个规则使用这个值不再是未定义的行为。
因此,该对象具有不确定的值。然后是指针是否可能具有陷阱表示的问题。如果指针在所使用的 C 实现中没有陷阱表示,则不会因为仅引用该值而发生陷阱,就像将其作为参数传递时一样。
result with Clang 6.0.0 at Compiler Explorer是没有设置参数寄存器的 jmp
指令,即使 -Wall -Werror
添加到编译器选项。相反,如果删除 (void)
行,则会导致编译器错误。
关于c - 有没有一种安全的方法来指定一个对象的值可能因为从未使用过而未初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50020196/
背景 我最近在 merge 期间遇到了一个意外未 merge 的文档文件的问题。 无论出于何种原因,我搞砸了 merge 并有效地删除了文件(和其他几个文件),因为我忘记了它们的存在。 现在我想查看我
我在我的网站上使用旧的 mysql 版本和 php 版本 4。 我的表结构: | orders_status_history_id | orders_id | orders_status_id |
我是一名优秀的程序员,十分优秀!