C 函数定义和 Extern 关键字

Posted

技术标签:

【中文标题】C 函数定义和 Extern 关键字【英文标题】:C Function Definition and the Extern Keyword 【发布时间】:2013-06-21 04:17:07 【问题描述】:

我一直在尝试理解我得到的关于 _sbrk 函数的链接错误,并在库中偶然发现了这个函数定义。

extern caddr_t _sbrk(int incr);

// ... some other definitions ...

extern caddr_t _sbrk(int incr)

static unsigned char *heap = NULL;
unsigned char *prev_heap;

if (heap == NULL) 
    heap = (unsigned char *)&_end;

prev_heap = heap;

heap += incr;

return (caddr_t) prev_heap;

现在,我知道extern 在函数声明中的作用,但我不知道在函数定义中使用它的含义...

有谁知道extern这样使用是什么意思?

有问题的文件位于 asf/sam/utils/syscalls/gcc/syscalls.c 目录中的 Atmel 软件框架 (ASF) 中。

它在嵌入式环境中,我收到一堆与缺少_exit_kill_sbrk...的定义有关的链接错误。

生成存根是有意义的,但我希望至少给定的_sbrk 定义会起作用?

更新:

好的,看来添加一些关于我如何将所有这些链接在一起的信息可能会有所帮助。

我有一个可执行项目(使用 GCC 构建),我有一个链接到生成的可执行文件(也使用 GCC 构建)的静态库项目。

它们都没有启用优化(它可以更轻松地在嵌入式目标上进行调试,而不会像在药物上那样跳跃)。

静态库包含上面提到的 ASF 代码。 ASF 由 Atmel Studio 6.0 中包含的某个向导自动生成。

静态库中的一些代码包括<stdio.h>,这对我的目的来说不是必需的,但我真的不想更改自动生成的代码(它必然会撤消我的更改)。

来自链接器的错误如下:

Invoking: ARM/GNU Linker : (crosstool-NG 1.15.3 - Atmel build: 59) 4.7.0
    "C:\Program Files (x86)\Atmel\Atmel Studio 
6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMGCCToolchain\bin\arm-none-eabi-gcc.exe" -o 
Bootloader_Stage1.elf  cmsis/src/startup_sam3n.o cmsis/src/system_sam3n.o 
Bootloader_Stage1.o   -Wl,-Map="Bootloader_Stage1.map" -Wl,--start-group -lm -
lBootloaderShared  -Wl,--end-group -L"../cmsis/linkerScripts" -
L"../../BootloaderShared/Debug"  -Wl,--gc-sections -Tsam3n4b_flash.ld  -mcpu=cortex-m3 
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-abort.o): In function 
`abort':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/stdlib/abort.c(63,1): undefined reference to `_exit'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-sbrkr.o): In function 
`_sbrk_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/sbrkr.c(60,1): undefined reference to `_sbrk'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function 
`_kill_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(61,1): undefined reference to `_kill'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function 
`_getpid_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(96,1): undefined reference to `_getpid'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-writer.o): In function 
`_write_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/writer.c(58,1): undefined reference to `_write'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-closer.o): In function 
`_close_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/closer.c(53,1): undefined reference to `_close'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-fstatr.o): In function 
`_fstat_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/fstatr.c(62,1): undefined reference to `_fstat'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-isattyr.o): In function 
`_isatty_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/isattyr.c(58,1): undefined reference to `_isatty'
    Invoking: ARM/GNU Linker : (crosstool-NG 1.15.3 - Atmel build: 59) 4.7.0
    "C:\Program Files (x86)\Atmel\Atmel Studio 
6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMGCCToolchain\bin\arm-none-eabi-gcc.exe" -o 
Bootloader_Stage1.elf  cmsis/src/startup_sam3n.o cmsis/src/system_sam3n.o 
Bootloader_Stage1.o   -Wl,-Map="Bootloader_Stage1.map" -Wl,--start-group -lm -
lBootloaderShared  -Wl,--end-group -L"../cmsis/linkerScripts" -
L"../../BootloaderShared/Debug"  -Wl,--gc-sections -Tsam3n4b_flash.ld  -mcpu=cortex-m3 
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-abort.o): In function 
`abort':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/stdlib/abort.c(63,1): undefined reference to `_exit'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-sbrkr.o): In function 
`_sbrk_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/sbrkr.c(60,1): undefined reference to `_sbrk'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function  
`_kill_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(61,1): undefined reference to `_kill'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-signalr.o): In function 
`_getpid_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/signalr.c(96,1): undefined reference to `_getpid'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-writer.o): In function 
`_write_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/writer.c(58,1): undefined reference to `_write'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-closer.o): In function 
`_close_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/closer.c(53,1): undefined reference to `_close'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-fstatr.o): In function 
`_fstat_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/fstatr.c(62,1): undefined reference to `_fstat'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-isattyr.o): In function 
`_isatty_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/isattyr.c(58,1): undefined reference to `_isatty'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-lseekr.o): In function 
`_lseek_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/lseekr.c(58,1): undefined reference to `_lseek'
    c:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-readr.o): In function 
`_read_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/readr.c(58,1): undefined reference to `_read'
collect2.exe(0,0): ld returned 1 exit statusc:/program files (x86)/atmel/atmel studio 
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-lseekr.o): In function 
`_lseek_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/lseekr.c(58,1): undefined reference to `_lseek'
    c:/program files (x86)/atmel/atmel studio  
6.0/extensions/atmel/armgcc/3.3.1.128/armgcctoolchain/bin/../lib/gcc/arm-none-
eabi/4.7.0/../../../../arm-none-eabi/lib/thumb\libc.a(lib_a-readr.o): In function 
`_read_r':
/usr/local/avr32studio/hudson/workspace/arm-gnu-toolchain/.build/src/newlib-
1.19.0/newlib/libc/reent/readr.c(58,1): undefined reference to `_read'
collect2.exe(0,0): ld returned 1 exit status

更新 2:

我已经解决了我的链接问题。似乎 Atmel 软件框架包括 #include <assert.h>,它是调用所有其他函数的那个​​。在该标头中,assert() 宏定义如下

#ifdef NDEBUG           /* required by ANSI standard */
# define assert(__e) ((void)0)
#else
# define assert(__e) ((__e) ? (void)0 : __assert_func (__FILE__, __LINE__, \
                           __ASSERT_FUNC, #__e))

定义 NDEBUG 后,链接问题就消失了。据我所知,NDEBUG 没有在其他任何地方使用(没有删除我依赖的任何其他代码),所以我可以保留定义的符号。

正如我之前提到的,我已经接受了回答 extern 问题的答案,并投票给了有助于解决链接问题的答案。

【问题讨论】:

你在链接它吗?我不认为那些 extern 关键字做任何事情 要了解extern,请查看L1。 @Carl Norum 是的,我正在链接它,但它有点复杂,所以我会更新我的问题。 @Koushik 天哪,答案很长!我已经明白了,但我想确保我没有遗漏任何东西。不过,谢谢,总是一个很好的复习。正如我所说,我会用我在做什么的细节来更新我的问题。 我认为这个答案与您的情况无关。它几乎没有谈论函数,无论如何默认函数是extern 【参考方案1】:

在函数声明中指定extern 没有问题。来自 C99 6.9.1/4“函数定义”:

语法

function-definition:
    declaration-specifiers declarator declaration-list[opt] compound-statement

...

声明说明符中的存储类说明符(如果有)应为externstatic

但是,函数定义上的extern 并不是特别有用。来自 C99 6.2.2/4“标识符的链接”:

对于使用存储类说明符extern 声明的标识符,在该标识符的先前声明可见的范围内,如果先前声明指定内部或外部链接,则后面声明的标识符的链接是与先前声明中指定的链接相同。如果前面的声明不可见,或者前面的声明没有指定链接,则标识符具有外部链接。

如果函数标识符的声明没有存储类说明符,则它的链接将完全确定,就好像它是使用存储类说明符 extern 声明的一样。

因此,在函数的第一个声明之后,后续函数声明中的任何 extern 都会被忽略,即使第一个声明是 static

【讨论】:

谢谢,这就解释了。我还发现@Dayal rai 提到“函数定义也是函数声明”有助于理解。这也出现在您的答案中,但不是很明显。不管它是否被接受。再次感谢。【参考方案2】:

函数定义前面的extern只是表示该函数有外部链接(which it has anyway by default)

函数定义中不应该需要“extern”,只要声明有它并且已经在定义的编译中看到。 记住definitions are declarations also

【讨论】:

... 在原型/声明中也不需要它。没有static 声明的函数总是有外部链接。 您和迈克尔·伯尔的回答完美地解释了这一点。谢谢!【参考方案3】:

在对链接问题的部分回答中,链接器抱怨它没有链接在一起的任何东西,例如目标文件(可能还有预编译的库),包括 _sbrk() 函数,该函数由 中的代码调用。其他几个低级库函数也是如此。

extern 不会影响您的问题。

【讨论】:

你是对的,我找到了我的问题所在。我将用我找到的解决方案更新我的问题。谢谢

以上是关于C 函数定义和 Extern 关键字的主要内容,如果未能解决你的问题,请参考以下文章

extern关键字

extern和extern "C"

extern关键字详解

C/C++中extern关键字详解

C语言中extern的意思是啥?

C/C++中extern关键字详解