You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GCC中ferror自定义编译报错解析:无定义调用仍编译原因

问题

我正在开发LCD显示屏的嵌入式C代码,其中一个文件包含<stdio.h>并定义fputc、fgetc和ferror函数。fputc调用LCD驱动打印字符,其余两函数无实际功能。编译时出现报错:

src/ST7735.c:1578:5: error: expected identifier or '(' before 'int'
1578 | int ferror(FILE *f){
src/ST7735.c:1578:5: error: expected ')' before '(' token
1578 | int ferror(FILE *f){

将ferror重命名后报错消失,另外两函数无问题。重命名后调用ferror仍可编译,按预期应因无定义链接失败。我使用arm-none-eabi工具链并加-nostdlib选项,项目原由Keil创建,想知道GCC中ferror是否有特殊处理?

回答

这是因为GCC对<stdio.h>里的ferror做了宏定义替换,这是它的特殊处理逻辑。

在GCC配套的<stdio.h>实现中,ferror通常被定义成一个宏,比如类似这样的形式:

#define ferror(_stream)  ((_stream)->_flags & __SERR)

当你包含<stdio.h>后,预处理器会先把你代码里的ferror替换成宏展开的内容,这就导致你写的函数定义完全不符合C语法,自然会报那些编译错误。

而fputc和fgetc虽然也可能是宏,但在嵌入式GCC的头文件实现中,它们的宏定义要么允许用户重定义,要么不会和自定义函数的语法冲突,所以这两个函数能正常编译。

至于重命名后调用原ferror还能通过编译的原因:就算加了-nostdlib,GCC的预处理器依然会处理<stdio.h>里的宏。你调用ferror时,编译器直接把它替换成了宏对应的代码,根本不会把它当成函数调用,所以不会触发未定义符号的链接错误。

如果要自己实现ferror函数,有两种可行方案:

  • 在包含<stdio.h>之后,用#undef ferror取消宏定义,再编写自己的函数实现
  • 给自定义函数换个名称(就是你目前采用的办法)

内容的提问来源于stack exchange,提问作者David D.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:20:48