昨晚有人问我一个 C 的问题,我不知道答案,因为我从大学开始就没有经常使用 C,所以我想也许我可以在这里找到答案,而不是忘记它。
如果一个人有一个定义,例如:
#define count 1
该人可以使用其中的 1 找到变量名称count
吗?
我不这么认为,因为我认为计数会指向 1,但看不到 1 如何指向计数。
昨晚有人问我一个 C 的问题,我不知道答案,因为我从大学开始就没有经常使用 C,所以我想也许我可以在这里找到答案,而不是忘记它。
如果一个人有一个定义,例如:
#define count 1
该人可以使用其中的 1 找到变量名称count
吗?
我不这么认为,因为我认为计数会指向 1,但看不到 1 如何指向计数。
基于@Cade Roux 的回答,如果您使用预处理器#define 将值与符号相关联,则一旦预处理器运行,代码将不会对该符号有任何引用:
#define COUNT (1)
...
int myVar = COUNT;
...
预处理器运行后:
...
int myVar = (1);
...
正如其他人所指出的,这基本上意味着“不”,出于上述原因。
简单的答案是否定的,他们不能。#Defines 这样的定义由预处理器处理,它们只指向一个方向。当然,另一个问题是即使编译器也不知道——因为“1”可以指向任何东西——多个变量可以同时具有相同的值。
那个人能用里面的 1 找到变量名“count”吗?
不
正如我确信比我更有说服力和精通的人会指出#define'd 的东西没有编译到源代码中,你所拥有的是一个预处理器宏,它将通过源代码并更改所有实例 'count ' 它找到一个 '1'。
但是,为了更清楚地说明您被问到的问题,因为 C 是一种编译语言,直到机器代码,您永远不会对 Java 或 C# 等语言进行反射和自省。除非你有一个围绕你的源代码/编译器构建的框架来做一些漂亮的事情,否则编译后所有的命名都会丢失。
希望这会有所帮助。(请原谅双关语)
不幸的是,这是不可能的。
#define
语句是预处理器的指令,所有实例count
都替换为1
. 在运行时没有与 关联的内存位置count
,因此努力显然是徒劳的。
即使您使用变量,编译后也不会残留程序中使用的原始标识符。这通常仅在动态语言中才有可能。
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 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) {
...
}
C 定义是预处理器指令,而不是变量。在编译之前,预处理器将遍历您的 C 文件并用您定义的内容替换您编写 count 的位置。查看混淆的 C 竞赛条目,了解此和其他预处理器指令的一些特别开明的用途。
关键是没有“计数”指向“1”值。它只是在代码真正编译之前发生的简单/查找替换操作。
我会将这个可编辑的内容留给真正了解 C 的人来纠正。
count
不是变量。它没有分配给它的存储空间,也没有符号表中的条目。在将源代码传递给编译器之前,它是一个被预处理器替换的宏。
如果您没有提出完全正确的问题,有一种方法可以使用宏获取名称:
#define SHOW(sym) (printf(#sym " = %d\n", sym))
#define count 1
SHOW(count); // prints "count = 1"
运算符将#
宏参数转换为字符串文字。
“发现”是什么意思?
线
#define count 1
定义一个值为 1 的符号“count”。
编译过程的第一步(称为预处理)会将每次出现的符号计数替换为 1,这样如果您有:
if (x > count) ...
它将被替换为:
if (x > 1) ...
如果你明白了,你可能会明白为什么“查找计数”是没有意义的。
#define
是预处理器指令,因此它不是“变量”
你所拥有的实际上不是一个变量,它是一个预处理器指令。当您编译代码时,预处理器将通过并将该文件中单词“count”的所有实例替换为 1。
你可能会问我是否知道 1 我可以找到 count 指向它吗?不,因为变量名称和值之间的关系不是双射,所以没有退路。考虑
int count = 1;
int count2 = 1;
完全合法,但 1 应该解决什么问题?
一般来说,没有。
首先,#define 不是变量,它是编译器预处理器宏。
到编译器的主要阶段开始工作时,名称已被替换为值,并且名称“count”将不存在于编译的代码中的任何地方。
对于变量,在运行时无法在 C 代码中找出变量名。不保留该信息。与 Java 或 C# 等语言不同,C 在编译为汇编语言时根本不保留太多元数据。
以“#”开头的指令由预处理器处理,该预处理器通常在将代码传递给“真实”编译器之前进行文本替换。因此,没有名为 count 的变量,就好像代码中的所有“count”字符串都被神奇地替换为“1”字符串。
所以,不,没有办法找到那个“变量”。
如果是宏,则会对其进行预处理并编译生成的输出。所以绝对没有办法找出这个名字,因为在预处理器完成他的工作后,生成的文件将在文件中的任何地方包含“1”而不是“count”。
所以答案是否定的。
如果他们正在查看 C 源代码(他们将在调试器中),那么他们将看到类似
int i = count;
那时,他们可以向后搜索并找到该行
#define count 1
但是,如果他们所拥有的只是变量 iDontKnowWhat,并且他们可以看到它包含 1,则无法将其追溯到“计数”。
为什么?因为#define 是在预处理器时评估的,这甚至发生在编译之前(尽管对于几乎所有人来说,它可以被视为编译的第一阶段)。因此,源代码是唯一包含有关“计数”的任何信息的东西,就像知道它曾经存在过一样。到编译器查看时,对“count”的每个引用都已替换为数字“1”。
它不是一个指针,它只是一个字符串/令牌替换。预处理器会在您的代码编译之前替换所有#defines。大多数编译器都包含一个 -E 或类似的参数来发出预编译代码,因此您可以看到处理完所有#directives 后代码的样子。
更直接地回答您的问题,没有办法告诉代码正在替换令牌。您的代码甚至无法区分 (count == 1) 和 (1 == 1)。
如果您真的想这样做,则可以使用源文件文本分析,例如使用差异工具。
问这个问题的人(这是一个面试问题吗?)可能一直试图让你区分使用#define 常量和枚举。例如:
#define ZERO 0
#define ONE 1
#define TWO 2
对比
enum {
ZERO,
ONE,
TWO
};
给定代码:
x = TWO;
如果您使用枚举而不是 #defines,一些调试器将能够向您显示值的符号形式 TWO,而不仅仅是数值 2。