gcc没有给出冲突类型错误

时间:2017-03-09 23:03:02

标签: c gcc

我正在通过K& R2并编写一个小程序来测试7.7节中给出的fputs和fgets函数。当我编译时,我收到错误:' fputs'的冲突类型。我没有收到同样的错误' fgets'。根据我的理解,fput和fgets都在stdio.h中,为什么我只得到fput的错误?

如果我将fput重命名为fputs_77,则没有编译错误。如果没有重命名fgets,我怎么知道对它的调用(在getline函数中)是来自程序中的fgets函数而不是stdio.h?

我编译:

gcc -Wall -Wextra -ansi -pedantic -fno-builtin 7.7.c -o 7.7

#include <stdio.h>
#include <string.h>

#define MAXLINE 1000

char *fgets(char *s, int n, FILE *iop);
int fputs(char *s, FILE *iop);
int getline(char *line, int max);

/* demo of functions in 7.7 */
int main(void)
{
    char line[MAXLINE];
    while (getline(line, MAXLINE) > 0) {
        fputs(line, stdout);
    }
    return 0;
}

/* fgets:  get at most n chars from iop */
char *fgets(char *s, int n, FILE *iop)
{
    register int c;
    register char *cs;

    cs = s;
    while (--n > 0 && (c = getc(iop)) != EOF) {
        if ((*cs++ = c) == '\n') {
            break;
        }
    }
    *cs = '\0';
    return (c == EOF && cs == s) ? NULL : s;
}

/* fputs:  put string s on file iop */
int fputs(char *s, FILE *iop)
{
    int c;

    while ((c = *s++)) {    /* assignment */
        putc(c, iop);
    }
    return ferror(iop) ? EOF : 0;
}

/* getline:  read a line, return length */
int getline(char *line, int max)
{
    if (fgets(line, max, stdin) == NULL) {
        return 0;
    } else {
        return strlen(line);
    }
}

2 个答案:

答案 0 :(得分:1)

一般来说,如果所有声明都是兼容的,则允许多次声明函数(和变量)。你声明fgets()与stdio.h中相同函数的标准库声明兼容(实际上是相同的),并且你的编译器没有问题。您的fputs()也是如此。

您将该功能声明为

int fputs(char *s, FILE *iop);

,但在C99中,C标准库将其声明为

int fputs(const char *s, FILE *iop);

,在C11中,C标准库将其声明为

int fputs(const char * restrict s, FILE *iop);

。无论哪种方式,函数的第一个参数的额外限定符使标准库的声明与您的声明不兼容,这就是编译器所抱怨的。

由于您的编译器正在接受标准库函数的兼容重新声明和重新定义,因此您有两种可能的修复方法:

  1. 更改您的声明以匹配标准库或
  2. 避免直接或间接包含stdio.h。
  3. 另一方面,尽管有上述任何一点,但请注意,重新声明或重新定义标准库函数的标识符作为外部函数,正如您所做的那样,每paragraph 7.1.3/2 of the standard生成一个未定义的行为。因此,即使您的声明相同,编译器也没有义务接受它,并且就C而言,运行时行为可以是任何东西。最远的 最佳 替代方法是提供不会与标准库发生冲突的函数名称。

答案 1 :(得分:0)

因为fgets()的declration / definition与<stdio.h>中的标准函数声明不冲突,所以你被允许 只要它们兼容,就有多个外部声明。

fputs()的声明与<stdio.h>中提供的标准声明不同。

注意:由于您正在重新定义标准功能,因此您的程序并不严格符合C标准。最好将功能重命名为其他功能 - 例如my_fgets()my_fputs()等。

虽然getline()不符合C标准,但它在POSIX标准中。所以,您可能也想重命名它。 -ansi等同于-std=c90 - 如果您碰巧在POSIX下编译,这可能会妨碍。您也可以将其重命名为my_getline()

  

如果不重命名fgets,我怎么知道对它的调用(在getline函数中)是来自程序中的fgets函数而不是stdio.h?

GNU链接器通常的符号解析顺序是程序中的符号首先出现。这意味着如果您提供兼容的声明(通过编译器诊断),那么您可以确定它是您的 fgets()。例如,您可以使用函数中的printf()语句轻松地对此进行测试。