编译错误

use*_*492 0 c compilation

我一直在创建一个应该打开文件的函数(catalogname []).但是每当我编译时,我都会得到这两个我无法弄清楚的错误.

a3.c:在函数'openCatalog'中:

a3.c:20:警告:从不兼容的指针类型分配

a3.c:22:警告:return在没有强制转换的情况下从整数生成指针

这是我的代码:

FILE* openCatalog(char catalogname[])
{
    catalogname = fopen ("*catalogname", "r");
    if(fopen != 0)
    {
        return 1;
    }
    else 
    {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

提前感谢您提供的任何见解.

Jon*_*ler 5

对此代码的完整解释将需要一段时间.

简要版本是:

FILE *openCatalog(char catalogname[])
{
    FILE *fp = fopen(catalogname, "r");
    return(fp);
}
Run Code Online (Sandbox Code Playgroud)

这将打开命名文件以进行读取并返回文件流指针.

另一个简短版本检查文件是否可以打开:

int openCatalog(char catalogname[])
{
    FILE *fp = fopen(catalogname, "r");
    if (fp != 0)
    {
        fclose(fp);
        return 1;
    }
    else 
    {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

注释

原始代码是:

FILE* openCatalog(char catalogname[])
{
    catalogname = fopen ("*catalogname", "r");
    if(fopen != 0)
    {
        return 1;
    }
    else 
    {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们没有"打开文件"之外的规范.给定函数签名,似乎您希望FILE *返回打开文件的(文件流指针).所以,让我们在此基础上批评代码.

  • 功能原型线是可以的; 可能是char const catalogname[]要强调该函数不会修改文件名,但这是一个改进,而不是修复错误.

  • catalogname函数的类型是char *.在函数的参数列表中,数组与指针松散等价.我通常会写FILE *openCatalog(char const *catalogname)一下,强调在函数中,它是一个char const *变量.尽管如此,使用您使用的数组符号是100%合法的; 对于我来说,使用指针符号纯粹是一种风格偏好.

  • 下一个可执行行有几个问题.函数调用在fopen()技术上并没有错,虽然它打开一个具有固定名称*catalogname的文件而不是变量中指定的文件catalogname.要解决此问题,您需要删除引号.该*会给你一个角色,而不是一个字符串,这将是文件名的第一个字符.所以,删除它*.

  • 这使您fopen()返回一个值,实际上是a FILE *,并将其分配给catalognamea char *.这是类型不匹配,编译器警告.如第一次重写所示,处理此问题的更常用方法是:

    FILE *fp = fopen(catalogname, "r");
    
    Run Code Online (Sandbox Code Playgroud)

    这会导致您的错误消息:

    a3.c:20: warning: assignment from incompatible pointer type
    
    Run Code Online (Sandbox Code Playgroud)
  • 我们不知道您的目录是文本文件还是二进制文件.如果它是一个二进制文件,那么你应该使用"rb"它来打开它,如果你在Windows(真正重要的地方),并且它也可以在类Unix系统上正常工作(文本和二进制文件之间没有区别).

  • 代码中的下一行是条件:

    if (fopen != 0)
    
    Run Code Online (Sandbox Code Playgroud)

    这实际上检查函数的函数指针是否fopen()为null.并且C标准保证在托管环境(您正在使用)中,没有函数指针为空.因此编译器可以优化该测试以假设条件始终为真.

    你真正需要的是对结果的测试:

    if (fp != 0)
    
    Run Code Online (Sandbox Code Playgroud)
  • 然后你有两个return语句,一个返回1,一个返回0.返回1返回1引发一个关于将整数转换为指针的警告,因为该函数被定义为返回a FILE *而1是一个整数.

    这会解释您的其他警告消息:

    a3.c:22: warning: return makes pointer from integer without a cast
    
    Run Code Online (Sandbox Code Playgroud)
  • 返回0不会生成警告,因为0是空指针常量,并且这是要返回的函数的有效值.

  • 代码应该只是简单地返回值fopen().在此函数或调用函数中测试某处的值是正确的,以确保打开成功.你可以在这里测试它:

    if (fp == 0)
        err_report_and_exit("Failed to open file %s (%d: %s)\n",
                            catalogname, errno, strerror(errno));
    
    Run Code Online (Sandbox Code Playgroud)

    使用errnostrerror()意味着您还应该包含标题:

    #include <errno.h>
    #include <string.h>
    
    Run Code Online (Sandbox Code Playgroud)
  • 代码应从以下位置返回文件流fopen():

    return fp;
    
    Run Code Online (Sandbox Code Playgroud)

总的来说,这会导致:

FILE *openCatalog(char catalogname[])
{
    FILE *fp = fopen(catalogname, "r");
    if (fp == 0)
        err_report_and_exit("Failed to open file %s (%d: %s)\n",
                            catalogname, errno, strerror(errno));
    return(fp);
}
Run Code Online (Sandbox Code Playgroud)

如果该函数旨在检查文件是否可以打开以供阅读,则上述问题大致相同.我首先展示的修订代码略显冗长.由于推测的目的是检查文件是否可以打开,因此调用代码应负责处理"它无法打开的情况"; 它知道要生成什么样的诊断.这是一个稍微复杂的版本,但是这个和上面的对象代码是相同的.

int openCatalog(char catalogname[])
{
    FILE *fp = fopen(catalogname, "r");
    if (fp != 0)
    {
        fclose(fp);
        return 1;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

一个简单的实现err_report_and_exit()是:

#include "errreport.h"
#include <stdio.h>
#include <stdlib.h>
#include <starg.h>

void err_report_and_exit(char const *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    exit(EXIT_FAILURE);
}
Run Code Online (Sandbox Code Playgroud)

"errreport.h"标题可能是:

#ifndef ERRREPORT_H_INCLUDED
#define ERRREPORT_H_INCLUDED

#ifdef __GNUC__
#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
#define NORETURN()      __attribute__((noreturn))
#else
#define PRINTFLIKE(n,m) /* If only */
#define NORETURN()      /* If only */
#endif /* __GNUC__ */

extern void err_report_and_exit(char const *format, ...) PRINTFLIKE(1,2) NORETURN();

#endif /* ERRREPORT_H_INCLUDED */
Run Code Online (Sandbox Code Playgroud)

特定于GCC的位意味着您可以获得与printf()直接使用相同级别的格式错误报告.

(这段代码是在一个更大的包上建模的,系统地err_用作函数前缀.在这个包中,这个函数就是err_error().这就是为什么它err_不是error_- 尽管解释需要的时间比修复它要长.包含在文件stderr.cstderr.h,虽然有它如履薄冰使用踏入参数std前缀.它是,但是,我的标准错误报告包).