保护功能声明不编译

时间:2016-08-19 14:29:41

标签: c gcc makefile

我使用#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

2 个答案:

答案 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文件发出存根代码。但是在链接阶段,找不到这些函数的定义,因为它们被预处理器省略。因此,链接错误。