我正在遍历K&R2,并编写了一个小程序来测试7.7节中给出的fputs和fgets函数。编译时,我收到错误消息:“ fputs”的类型冲突。我没有收到相同的“ fgets”错误。据我了解,fputs和fgets都在stdio.h中,所以为什么我只收到fputs错误?

如果将fputs重命名为fputs_77,则没有编译错误。在不重命名fget的情况下,我怎么知道对它的调用(在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);
    }
}

最佳答案

一般来说,只要所有声明都兼容,就可以多次声明函数(和变量)。您可以与stdio.h中的相同函数的标准库声明(实际上相同)声明fgets(),并且编译器对此没有任何问题。您的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);


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

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


更改声明以符合标准库的声明,或者
避免直接或间接包含stdio.h。


另一方面,尽管有上述任何规定,但请注意,正如您所做的那样,将标准库函数的标识符重新声明或重新定义为外部函数时,会根据paragraph 7.1.3/2 of the standard产生未定义的行为。这样,即使您的声明相同,编译器也没有义务接受它,并且就C而言,运行时行为可以是任何东西。最好的选择是为函数提供不与标准库冲突的名称。

关于c - gcc没有给出冲突的类型错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42707186/

10-10 20:35