在C中查找变量的名称
昨晚我在C语言中被问到一个问题,因为我从大学开始就没有使用C语言,所以我不知道答案,所以我想也许我可以在这里找到答案,而不仅仅是忘记它。
如果某人具有以下定义:
#define count 1
该人可以使用其中的1查找变量名count
吗?
我不这么认为,因为我认为计数将指向1,但看不到1如何指向计数。
解决方案
"查找"是什么意思?
线
#define count 1
定义值为" 1"的符号" count"。
编译过程的第一步(称为预处理)将用1替换每次出现的符号计数,以便在满足以下条件的情况下:
if (x > count) ...
它将被替换为:
if (x > 1) ...
如果理解了这一点,我们可能会明白为什么"查找计数"没有意义。
#define是预处理程序指令,因此它不是"变量"
C定义是预处理程序指令,而不是变量。预处理程序将遍历C文件,并在编译之前用我们定义的位置替换我们在其中写入count的位置。请查看混淆的C竞赛条目,以了解此指令和其他预处理程序指令的某些特别开明的用法。
关键是没有指向" 1"值的"计数"。这只是在代码真正编译之前进行的简单/查找替换操作。
我会将这个可编辑的内容留给实际上真正了解C的人来解决。
Can that person find the variable name "count" using the 1 that is inside it?
不
简单的答案是不,他们不能。 #这样的定义由预处理器处理,它们仅指向一个方向。当然,另一个问题是,即使编译器也不知道" 1"可能指向多个变量,而这些变量可以同时具有相同的值。
因为我敢肯定有人比我更有说服力和经验,所以会指出#define的东西未编译到源代码中,所以我们拥有的是预处理器宏,它将通过源代码并更改所有'count实例会找到一个'1'。
但是,为了更加清楚地询问我们所提出的问题,因为C是一种经过编译的语言,直至机器代码,所以我们再也不会像Java或者C#这样的语言得到反思和反省。除非我们有一个围绕源代码/编译器构建的框架来做一些漂亮的事情,否则所有名称在编译后都会丢失。
希望这可以帮助。 (打扰)
实际上,我们所拥有的不是变量,而是预处理器指令。编译代码时,预处理器将遍历并将该文件中单词" count"的所有实例替换为1.
我们可能会问我是否知道1我能找到该点数吗?不会。因为变量名称和值之间的关系不是双射的,所以没有回头路了。考虑
int count = 1; int count2 = 1;
完全合法,但1应该解决什么?
以@Cade Roux的答案为基础,如果使用预处理器#define将值与符号相关联,则在预处理器运行后,代码将不会对该符号进行任何引用:
#define COUNT (1) ... int myVar = COUNT; ...
预处理程序运行后:
... int myVar = (1); ...
因此,正如其他人所指出的,由于上述原因,这基本上表示"否"。
一般来说,不可以。
首先,#define不是变量,它是编译器预处理器宏。
到编译器的主要阶段开始工作时,该名称已替换为值,并且名称" count"在已编译的代码中的任何位置都将不存在。
对于变量,在运行时无法在C代码中找到变量名称。该信息不会保留。与Java或者C#等语言不同,C在编译成汇编语言时根本不保留太多元数据。
以"#"开头的指令由预处理器处理,该预处理器通常在将代码传递给"实际"编译器之前进行文本替换。这样,就没有名为count的变量,就好像代码中的所有" count"字符串都神奇地替换为" 1"字符串一样。
因此,不,没有找到该"变量"的方法。
如果是宏,则对其进行预处理,并编译结果输出。因此,绝对没有办法找到该名称,因为在预处理器完成他的工作之后,结果文件将在文件中的所有位置包含" 1"而不是" count"。
所以答案是否定的。
不幸的是,这是不可能的。
" #define"语句是预处理器的指令,所有" count"实例都被" 1"替换。在运行时,没有与" count"关联的内存位置,因此工作显然是徒劳的。
即使我们使用变量,编译后也不会残留程序中使用的原始标识符。通常这仅在动态语言中才有可能。
如果他们正在查看C源代码(它们将在调试器中),那么他们将看到类似
int i = count;
在那时,他们可以搜索并找到线
#define count 1
但是,如果他们拥有的只是变量iDontKnowWhat,并且可以看到它隐含1,则无法将其追溯到"计数"。
为什么?因为#define是在预处理程序时评估的,所以甚至在编译之前都会进行评估(尽管对于几乎每个人来说,它都可以视为编译的第一阶段)。因此,源代码是唯一具有有关"计数"的任何信息的东西,就像知道它曾经存在一样。到编译器查看时,所有对" count"的引用已被数字" 1"代替。
它不是指针,只是字符串/令牌替换。在代码编译之前,预处理器将替换所有#define。大多数编译器都包含-E或者类似的参数来发出预编译的代码,因此我们可以在处理所有#指令后查看代码的样子。
对于问题,更直接的是,没有办法告诉我们代码中已替换了令牌。代码甚至无法分辨(count == 1)和(1 == 1)之间的区别。
如果我们确实想这样做,则可以使用源文件文本分析,例如使用diff工具。
C语言中使用的一种技巧是使用宏中的语法来获取宏参数的字符串文字。
#define displayInt(val) printf("%s: %d\n",#val,val) #define displayFloat(val) printf("%s: %d\n",#val,val) #define displayString(val) printf("%s: %s\n",#val,val) int main(){ int foo=123; float bar=456.789; char thud[]="this is a string"; displayInt(foo); displayFloat(bar); displayString(thud); return 0; }
输出应类似于以下内容:
foo: 123 bar: 456.789 thud: this is a string
提出问题的人(是否是面试问题?)可能一直在试图让我们区分使用#define常量还是枚举。例如:
#define ZERO 0 #define ONE 1 #define TWO 2
与
enum { ZERO, ONE, TWO };
给定代码:
x = TWO;
如果我们使用枚举而不是#defines,则某些调试器将能够向我们显示值的符号形式TWO,而不只是数字值2.
" count"不是变量。它没有分配存储空间,符号表中也没有条目。这是一个宏,在将源代码传递给编译器之前,该宏将被预处理器替换。
如果我们没有提出正确的问题,可以使用宏来获取名称:
#define SHOW(sym) (printf(#sym " = %d\n", sym)) #define count 1 SHOW(count); // prints "count = 1"
#操作符将宏参数转换为字符串文字。
" #define count 1"是一个非常糟糕的主意,因为它阻止我们命名任何变量或者结构字段" count"。
例如:
void copyString(char* dst, const char* src, size_t count) { ... }
count
宏将导致变量名被1
替换,从而阻止了该函数的编译:
void copyString(char* dst, const char* src, size_t 1) { ... }