我使用#define保护头文件中的函数,我通过命令行将其添加为全局编译标志。这是为了减少我不使用某些代码时的整体二进制大小。
我以为我可以在头文件中保护它们,并且c文件中的函数会自动编译出来。这不是为我编译的。 Make报告该函数未声明。我必须在C文件中的函数周围放置保护,以使其编译正常。
这是预期的行为还是应该保护功能声明就足够了。
标头文件
#ifndef __LOGIC_H__
#define __LOGIC_H__
#include "test.h"
#if (HAS_SPI)
int test_spi_config(void);
int test_spi_transfer(void);
#endif
#endif /* __LOGIC_H__ */
C档
#include "logic.h"
#if (HAS_SPI) /* Wont compile without this */
int test_spi_config(void) {
/* code */
}
#if (HAS_SPI) /* Wont compile without this */
int test_spi_transfer(void) {
/* code */
}
#endif
#endif
答案 0 :(得分:0)
预处理器执行简单的文本转换。它根本不了解C。特别是,它不了解函数的声明或定义;它不知道或不关心它正在解析的文本是否是函数的一部分,特别是它不知道它正在处理哪个函数。
我认为如果标题包含:
,则期待您#if HAS_SPI
extern int test_spi_config(void);
#endif
并且实现文件具有:
int test_spi_config(void)
{
…
return 0;
}
然后编译器本身不会显示test_spi_config()
的代码,因为标题没有声明它。
这是一个不准确的期望。预处理器没有看到#
围绕函数定义启动的行,并且此讨论中没有可以更改源代码文本的宏(例如,没有#define test_spi_config() rand()
) ,所以函数定义只是复制到主编译器。
函数定义本身必须受与原型声明等效(最好是相同)条件的保护:
#if HAS_SPI
int test_spi_config(void)
{
…
return 0;
}
#endif
因此,在您的问题中,标题中有条件定义的原型不会影响函数周围的文本;你需要明确的测试。
您还应该以适当的test_spi_config()
/ test_spi_transfer()
条件将对#if HAS_SPI
或#endif
的每次通话都包含在内。这可能会对周围的逻辑产生影响,因此所包含的块可能比单个函数调用大 - 特别是如果您需要测试或保存test_spi_config()
的返回值(如果您不是,为什么函数首先返回一个值?)。
#if HAS_SPI
请注意,这些条件通常写为#ifdef HAS_SPI
或#if defined(HAS_SPI)
,因此定义HAS_SPI
的内容无关紧要。对于#if
条件,如果某处有#define HAS_SPI 0
(或等效的命令行),则代码将被省略,而defined
变量则包含该代码。哪个是正确的取决于您的需求 - 但使用#ifdef
比#if
更常见。
保持一致更为重要 - 始终使用#if
或始终使用#ifdef
- 比使用的更为重要。
答案 1 :(得分:-1)
是的,这绝对是正常的。
C编译器查看test_spi_*
函数的声明,并为包含logic.h的每个.c文件发出存根代码。但是在链接阶段,找不到这些函数的定义,因为它们被预处理器省略。因此,链接错误。