我对如何在 c(C99 及更高版本)中内联函数感到困惑。在“C 编程,一种现代方法”(K.N. King,第 2 版)的第 18.6 节中,或者例如 this 中的 3教程(在“使用内联函数的策略”下),内联函数的定义在头 (.h) 文件中给出,然后该函数在源 (.c) 文件中再次列为 extern。
例如,我在做什么:在 header “stencil.h”中
#ifindef _STENCIL_H
#define _STENCIL_H
inline double D1_center_2ndOrder(double vp1, double vm1, double dr)
{
return (vp1-vm1) / (2.0 * dr) ;
}
#endif
然后在匹配的源文件“stencil.c”中定义
#include "stencil.h"
extern double D1_center_2ndOrder(double vp1, double vm1, double dr) ;
我这样做了,然后在文件“main.c”中我调用了 average:
#include <stdio.h>
#include <stdlib.h>
#include "stencil.h"
int main(int argc, char *argv[])
{
double vp1 = 1 ;
double vp2 = 2 ;
dr = 0.1 ;
double der_v = D1_center_2ndOrder(vp1, vm1, dr) ;
printf("der_v\t%f\n", der_v) ;
return 0 ;
}
我用下面的makefile编译一切
CC = gcc
CFLAGS = -Wall -lm -std=gnu11
OBJECTS = main.o stencil.o
DEPS_MAIN = stencil.h
test: $(OBJECTS)
$(CC) -o collapse $(OBJECTS) $(CFLAGS)
main.o: main.c $(DEPS_MAIN)
$(CC) -c main.c
stencil.o: stencil.c stencil.h
$(CC) -c stencil.c
然后我得到以下编译器错误:
gcc -c main.c
gcc -c stencil.c
gcc -o test main.o stencil.o -Wall -lm -std=gnu11
stencil.o: In function `D1_center_2ndOrder':
stencil.c:(.text+0x0): multiple definition of `D1_center_2ndOrder'
main.o:main.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [collapse] Error 1
当我在 .c 源文件“stencil.c”中定义函数并在头文件中声明它时,我没有收到上述错误。我使用的 gcc 版本是 gcc (GCC) 4.8.5 20150623(红帽 4.8.5-28)。
我的问题是:
(1) 为什么“C 编程,一种现代方法”和我在网上找到的关于内联函数的教程建议在头文件中定义函数并在源文件中再次将其列为 extern?这样做会给我一个编译器错误。
(2) 当我在头文件中声明内联函数然后在源文件中定义为 extern 时,编译器是否仍会内联我的函数?
最佳答案
您使用的是基于标准 C99(及更新版本)的可移植策略,这是完全正确的。
失败是因为您使用默认的 -std
设置调用 gcc,对于 GCC 4.8.5,这有效地告诉它使用其遗留语义而不是标准 C11 语义。 -std
的默认值在 4.8.5 版中是 gnu90
。在版本 5 中,它被更改为 gnu11
,它实现了 C99/C11 inline
语义。
您正在使用默认设置,因为您的 Makefile 没有在编译配方中包含 $(CFLAGS)
;仅在最终链接配方中。 (您可以在 make
打印出的命令中看到这一点)。
虽然 -std=gnu11
应该可以工作,但最好改用 -std=c11
。并考虑升级到更新的 GCC 版本。
关于c - 头文件与源文件中的内联函数定义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53051814/