在GCC中,-D__USE_FIXED_PROTOTYPES__用于什么?

3
在书籍 《实用C编程》 的第七章“编程过程”中,有一个Makefile文件:
File: calc1/makefile.gcc
#-----------------------------------------------#
#   Makefile for unix systems       #
#    using a GNU C compiler         #
#-----------------------------------------------#
CC=gcc
CFLAGS=-g -D__USE_FIXED_PROTOTYPES__ -ansi
#
# Compiler flags:
#   -g  -- Enable debugging
#   -Wall   -- Turn on all warnings (not used since it gives away
#           the bug in this program)
#   -D__USE_FIXED_PROTOTYPES__
#       -- Force the compiler to use the correct headers
#   -ansi   -- Don't use GNU extensions.  Stick to ANSI C.

calc1: calc1.c
    $(CC) $(CFLAGS) -o calc1 calc1.c

clean:
    rm -f calc1 

什么是“正确的标头”?为什么在选项参数-D__USE_FIXED_PROTOTYPES__之间没有空格?
GCC镜像中,有:
/* __USE_FIXED_PROTOTYPES__ used to be required to get prototypes for
   malloc, free, etc. on some platforms.  It is unclear if we still
   need it, but it can't hurt.  */
#define __USE_FIXED_PROTOTYPES__

这里有来自Re: 是否真的需要__USE_FIXED_PROTOTYPES__的解释。

但我没有理解重点。

这本PRACC书于1997年出版,有些过时但仍然非常有用。Makefile有点过时,我想知道是否还需要.gcc扩展名。

《实用C编程》勘误表中都没有提到这两个问题。


-D__USE_FIXED_PROTOTYPES__ 之间的空格是可选的。请注意,-ansi 标志已经过时,您现在应该使用其中之一:-std=c90(这就是 -ansi 的意思,或多或少),或者 -std=c99-std=c11(最好是后者),或者使用 GNU 变体之一(例如 -std=gnu11 - 这是 GCC 7 中的默认值(以及 6 和 5 IIRC,但不是早期版本的默认值)。 - Jonathan Leffler
2
在2017年使用一本1997年的编程书籍,出现2018年的错误,就像使用一本1307年的建筑书籍一样。 - Jonathon Reinhart
1
.gcc 后缀用于 makefile 可能是为了允许为不同的编译器编写不同的 makefile。如果您计划使用 GCC,则实际上不需要该后缀。它唯一的危害是您必须键入 make -f makefile.gcc 而不是只需键入 make,至少在您键入 ln -s makefile.gcc makefile(或 mv makefile.gcc makefile)之前是这样。__USE_FIXED_PROTOTYPES__ 的东西似乎在 20 年前是必要的;虽然如此,但在本千年的大部分时间里都不再需要。从 makefile 中删除它;它是现在无关紧要的历史材料。 - Jonathan Leffler
1
你能确认一下你使用的是这本书的哪个版本吗?是第三版吗? - Stargateur
1个回答

5
所有这些都是错误的。我不知道在2018年,也就是最新修订版2011年出版后的第7年,强迫编译器坚持1989年废弃标准修订版有什么实际意义。 __USE_FIXED_PROTOTYPES__ 的必要性似乎已经在1997年进行了讨论。它是为了使代码在头文件早于1989标准的平台上工作。你不会需要它。那时你可以编写一个程序,执行以下操作:
#include <stdlib.h>
int main() {
    void *p = malloc(42.0);
}

程序会出现未定义的行为,因为 <stdlib.h> 没有原型,并且参数类型不正确。
现在 GCC 不是这样工作的。自从 C99 以来,如果缺少原型,GCC 将大声抱怨。它还会抱怨关于错误的参数类型等问题:
// #include <stdlib.h>
int main() {
    void *p = malloc(42.0);
}

编译后:

% gcc test.c 
test.c: In functionmain’:
test.c:2:15: warning: implicit declaration of functionmalloc[-Wimplicit-function-declaration]
     void *p = malloc(42.0);
               ^~~~~~
test.c:2:15: warning: incompatible implicit declaration of built-in functionmalloc
test.c:2:15: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’

使用-pedantic-errors选项,隐式函数声明将成为一种错误,导致编译失败(这正是应该发生的)。

我甚至不确定现在是否会产生任何影响。据推测,这是为了修复声明,以便每当您包括<stdlib.h>时,例如malloc会有正确的原型,而不是隐式函数声明。它可能在20年前编译15年历史的系统时很重要。现在,它在编译35年历史的系统时才变得重要。

如果这是本书提供的实用建议之一,那么我的实用建议是将其用作燃料进行燃烧。这可能是您可以做的最有用的事情。

如果您重视标准符合性,可以使用以下方法替代所有这些标志:

-Wall -std=c11 -pedantic-errors

没有 -pedantic-errors,即使使用 -std=c11 -Wall,也会允许一些 GCC 特定的扩展滑过。

关于包含 include 的代码中,“with no includes” 注释有点令人困惑。而且在 C90 之前,你需要编写 extern char *malloc(); 来获取正确的返回类型 —— 它不是 void *,也没有一个标准头文件声明它。 - Jonathan Leffler
@JonathanLeffler 啊,那只是一个剩余的句子,在2018年谁有时间校对呢。 - Antti Haapala -- Слава Україні

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接