3

昨晚有人问我一个 C 的问题,我不知道答案,因为我从大学开始就没有经常使用 C,所以我想也许我可以在这里找到答案,而不是忘记它。

如果一个人有一个定义,例如:

#define count 1

该人可以使用其中的 1 找到变量名称count吗?

我不这么认为,因为我认为计数会指向 1,但看不到 1 如何指向计数。

4

18 回答 18

8

基于@Cade Roux 的回答,如果您使用预处理器#define 将值与符号相关联,则一旦预处理器运行,代码将不会对该符号有任何引用:

#define COUNT (1)
...
int myVar = COUNT;
...

预处理器运行后:

...
int myVar = (1);
...

正如其他人所指出的,这基本上意味着“不”,出于上述原因。

于 2008-09-24T14:16:50.243 回答
7

简单的答案是否定的,他们不能。#Defines 这样的定义由预处理器处理,它们只指向一个方向。当然,另一个问题是即使编译器也不知道——因为“1”可以指向任何东西——多个变量可以同时具有相同的值。

于 2008-09-24T14:16:06.207 回答
6

那个人能用里面的 1 找到变量名“count”吗?

于 2008-09-24T14:15:58.827 回答
5

正如我确信比我更有说服力和精通的人会指出#define'd 的东西没有编译到源代码中,你所拥有的是一个预处理器宏,它将通过源代码并更改所有实例 'count ' 它找到一个 '1'。

但是,为了更清楚地说明您被问到的问题,因为 C 是一种编译语言,直到机器代码,您永远不会对 Java 或 C# 等语言进行反射和自省。除非你有一个围绕你的源代码/编译器构建的框架来做一些漂亮的事情,否则编译后所有的命名都会丢失。

希望会有所帮助。(请原谅双关语)

于 2008-09-24T14:16:14.427 回答
3

不幸的是,这是不可能的。

#define语句是预处理器的指令,所有实例count都替换为1. 在运行时没有与 关联的内存位置count,因此努力显然是徒劳的。

即使您使用变量,编译后也不会残留程序中使用的原始标识符。这通常仅在动态语言中才有可能。

于 2008-09-24T14:17:27.107 回答
2

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
于 2008-09-24T14:25:48.367 回答
2

#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) {
   ...
}
于 2008-09-24T14:42:57.060 回答
1

C 定义是预处理器指令,而不是变量。在编译之前,预处理器将遍历您的 C 文件并用您定义的内容替换您编写 count 的位置。查看混淆的 C 竞赛条目,了解此和其他预处理器指令的一些特别开明的用途。

关键是没有“计数”指向“1”值。它只是在代码真正编译之前发生的简单/查找替换操作。

我会将这个可编辑的内容留给真正了解 C 的人来纠正。

于 2008-09-24T14:15:57.483 回答
1

count不是变量。它没有分配给它的存储空间,也没有符号表中的条目。在将源代码传递给编译器之前,它是一个被预处理器替换的宏。

如果您没有提出完全正确的问题,有一种方法可以使用宏获取名称:

#define SHOW(sym) (printf(#sym " = %d\n", sym))
#define count 1

SHOW(count); // prints "count = 1"

运算符将#宏参数转换为字符串文字。

于 2008-09-24T14:33:12.700 回答
0

“发现”是什么意思?

线

#define count 1

定义一个值为 1 的符号“count”。

编译过程的第一步(称为预处理)会将每次出现的符号计数替换为 1,这样如果您有:

if (x > count) ...

它将被替换为:

if (x > 1) ...

如果你明白了,你可能会明白为什么“查找计数”是没有意义的。

于 2008-09-24T14:14:19.377 回答
0

#define是预处理器指令,因此它不是“变量”

于 2008-09-24T14:14:46.257 回答
0

你所拥有的实际上不是一个变量,它是一个预处理器指令。当您编译代码时,预处理器将通过并将该文件中单词“count”的所有实例替换为 1。

你可能会问我是否知道 1 我可以找到 count 指向它吗?不,因为变量名称和值之间的关系不是双射,所以没有退路。考虑

int count = 1;
int count2 = 1;

完全合法,但 1 应该解决什么问题?

于 2008-09-24T14:16:36.657 回答
0

一般来说,没有。

首先,#define 不是变量,它是编译器预处理器宏。

到编译器的主要阶段开始工作时,名称已被替换为值,并且名称“count”将不存在于编译的代码中的任何地方。

对于变量,在运行时无法在 C 代码中找出变量名。不保留该信息。与 Java 或 C# 等语言不同,C 在编译为汇编语言时根本不保留太多元数据。

于 2008-09-24T14:16:51.897 回答
0

以“#”开头的指令由预处理器处理,该预处理器通常在将代码传递给“真实”编译器之前进行文本替换。因此,没有名为 count 的变量,就好像代码中的所有“count”字符串都被神奇地替换为“1”字符串。

所以,不,没有办法找到那个“变量”。

于 2008-09-24T14:16:59.230 回答
0

如果是宏,则会对其进行预处理并编译生成的输出。所以绝对没有办法找出这个名字,因为在预处理器完成他的工作后,生成的文件将在文件中的任何地方包含“1”而不是“count”。

所以答案是否定的。

于 2008-09-24T14:17:08.090 回答
0

如果他们正在查看 C 源代码(他们将在调试器中),那么他们将看到类似

int i = count;

那时,他们可以向后搜索并找到该行

#define count 1

但是,如果他们所拥有的只是变量 iDontKnowWhat,并且他们可以看到它包含 1,则无法将其追溯到“计数”。

为什么?因为#define 是在预处理器时评估的,这甚至发生在编译之前(尽管对于几乎所有人来说,它可以被视为编译的第一阶段)。因此,源代码是唯一包含有关“计数”的任何信息的东西,就像知道它曾经存在过一样。到编译器查看时,对“count”的每个引用都已替换为数字“1”。

于 2008-09-24T14:18:43.280 回答
0

它不是一个指针,它只是一个字符串/令牌替换。预处理器会在您的代码编译之前替换所有#defines。大多数编译器都包含一个 -E 或类似的参数来发出预编译代码,因此您可以看到处理完所有#directives 后代码的样子。

更直接地回答您的问题,没有办法告诉代码正在替换令牌。您的代码甚至无法区分 (count == 1) 和 (1 == 1)。

如果您真的想这样做,则可以使用源文件文本分析,例如使用差异工具。

于 2008-09-24T14:18:54.857 回答
0

问这个问题的人(这是一个面试问题吗?)可能一直试图让你区分使用#define 常量和枚举。例如:

#define ZERO 0
#define ONE 1
#define TWO 2

对比

enum {
  ZERO,
  ONE,
  TWO
};

给定代码:

x = TWO;

如果您使用枚举而不是 #defines,一些调试器将能够向您显示值的符号形式 TWO,而不仅仅是数值 2。

于 2008-09-24T14:26:11.157 回答