【问题标题】:Undefined reference to C Macro, but gets redefined error when I define it对 C 宏的未定义引用,但在我定义它时出现重新定义错误
【发布时间】:2020-02-23 08:30:24
【问题描述】:

我在 kthread.h 中定义了一个宏,如下所示。

#define KERNEL_THREAD_SAVED_KERENL_TOP_OFFSET 208

我正在尝试在 syscall.cc 中使用该宏

#include "syscall.h"
#include "kthread.h"

#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
  "movq " #offset "(%%" #reg "), %%rsp \n"

// .. and in some function
void func() {
  asm volatile(
    SET_KERNEL_THREAD_TOP_OFFSET(KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET, rbx)
:::);
}

如果我编译它,它会给出以下链接器错误。

syscall.cc:41: undefined reference to `KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET'

好的,我明白了。那么可能链接器没有找到宏?所以我也尝试在 .cc 中用一些不同的值来定义它。

#include "syscall.h"
#include "kthread.h"

#define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 100
#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
  "movq " #offset "(%%" #reg "), %%rsp \n"

然后,我得到一个编译器错误

./kernel/syscall.cc:5: error: "KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET" redefined [-Werror]
    5 | #define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 100
      | 
In file included from ./kernel/syscall.cc:3:
./kernel/kthread.h:7: note: this is the location of the previous definition
    7 | #define KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET 208
      | 

很明显,编译器知道 syscall.cc 中的 KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET。那为什么链接器看不到定义呢??

【问题讨论】:

  • #define KERNEL_THREAD_SAVED_KERENL_TOP_OFFSET 208 ... KERENL???
  • KERNEL_THREAD_SAVED_KERENL_TOP_OFFSET 中是否有相关的错字,即第二个 KERNEL 不应该是 KERENL?
  • 啊,这是我从我的代码复制到这里时犯的错字。无论如何,发布的答案解决了问题:p

标签: c++ c macros linker c-preprocessor


【解决方案1】:

链接器没有业务查找宏。宏由预处理器处理,它在链接器之前运行很长时间。如果链接器抱怨未定义的引用,则意味着您的宏扩展出错了。它会在不应该出现的地方发出KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET

问题出在

SET_KERNEL_THREAD_TOP_OFFSET(KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET, rbx)

这将扩展为

"movq " "KERNEL_THREAD_SAVED_KERNEL_TOP_OFFSET" "(%%" "rbx" "), %%rsp \n"

而您希望它扩展到(使用 kthread.h 中的值)

"movq " "208" "(%%" "rbx" "), %%rsp \n"

它发生的原因是如何处理像宏一样的函数的参数。在字符串化运算符# 中使用时,它们不会进行中间扩展。

您可以通过引入一个间接层来解决它。

#define SET_KERNEL_THREAD_TOP_OFFSET(offset, reg) \
  SET_KERNEL_THREAD_TOP_OFFSET_(offset, reg)
#define SET_KERNEL_THREAD_TOP_OFFSET_(offset, reg) \
  "movq " #offset "(%%" #reg "), %%rsp \n"

现在,当您尝试进行扩展时,它会分多次扩展。先到

SET_KERNEL_THREAD_TOP_OFFSET_(208, rbx)

rbx 不是宏的名称,因此它保持不变)。然后就变成了

"movq " "208" "(%%" "rbx" "), %%rsp \n"

【讨论】:

  • 啊甜蜜。谢谢!这修复了它
猜你喜欢
  • 2021-06-08
  • 2022-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多