编译错误

时间:2012-05-06 01:27:46

标签: 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;
    }
}

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

5 个答案:

答案 0 :(得分:5)

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

简要版本是:

FILE *openCatalog(char catalogname[])
{
    FILE *fp = fopen(catalogname, "r");
    return(fp);
}

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

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

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

诠释

原始代码是:

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

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

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

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

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

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

    FILE *fp = fopen(catalogname, "r");
    

    这说明了您的错误消息:

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

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

    if (fopen != 0)
    

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

    您实际需要的是对结果的测试:

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

    这说明了您的其他警告信息:

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

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

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

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

    #include <errno.h>
    #include <string.h>
    
  • 代码应返回fopen()的文件流:

    return fp;
    

总的来说,这导致:

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);
}

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

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

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);
}

“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 */

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

(此代码以更大的包为模型,系统地使用err_作为函数前缀。在该包中,此函数将为err_error()。这就是为什么它是err_而不是error_ stderr.c - 尽管解释所需的时间比解决它的时间要长。大包装包含在文件stderr.hstd中,尽管有一个论点是它正在踩着薄冰使用{{1}}前缀。但是,它是我的标准错误报告包。)

答案 1 :(得分:1)

  • 指针类型不兼容

    catalogname = fopen ("*catalogname", "r");
    

    catalogname是一个字符数组(char catalogname[]),而fopen()返回一个文件指针(FILE*)。当然,将文件指针赋给char数组(这是一种不同类型的指针 - 更重要的是,不可分配)没有任何意义。

  • return从没有强制转换

    的整数生成指针

    您声明您的函数在此处返回FILE*FILE* openCatalog(...)。但是,您的退货声明为return 1;return 0;。在那里,编译器认为你想要返回值为1(或0)的文件指针,因此响应。

答案 2 :(得分:1)

FILE* openCatalog(char catalogname[])

这会更好char *catalogname,因为你实际上没有通过数组 - 你得到一个指向角色的指针。 (这是C的一个有趣的小怪癖。)虽然这有效,但我发现提醒您只有非常欢迎指针。

catalogname = fopen ("*catalogname", "r");

fopen(3)会返回FILE*个对象。您无法将FILE*分配给char []变量。

如果您想在catalogname电话中使用fopen(3)变量,只需使用它:

FILE *f = fopen(catalogname, "r");
if(fopen != 0)
在此上下文中,

fopen函数指针。您不是将之前的fopen()调用的返回值与0进行比较,而是将函数指针0进行比较。那不是你想要的。

    return 1;

你声明你的函数返回FILE *,这就是你应该返回的 - 而不是整数。

重写版本如下:

FILE* openCatalog(char *catalogname) {
    FILE *f = fopen(catalogname, "r");
    if (!f)
        perror("Unable to open file");
    return f;
}

答案 3 :(得分:0)

实际上,你有很多错误,其中一些是被掩盖的

首先:

catalogename = fopen("*catalogname", "r");

错了。我想你想要的是:

FILE *fPtr = fopen(catalogname, "r");

然后,在那之后,你的函数的身体发生了很大的变化:

if (fPtr == NULL || ferror(fPtr) != 0) // if the file isn't NULL or if there is no errors with opening the file...
{
    if (fPtr != NULL) // never try to close a NULL file ...
        fclose(fPtr);

    return NULL; // best way to report an error in C - return NUL or set errno
}

else
{
     return fPtr; // return the file we just made.
}

答案 4 :(得分:0)

第一个警告:

您要将FILE*fopen返回的内容)分配给catalogname char []

第二个警告:

当您返回整数FILE*0

时,函数返回类型1

你还想要别的东西吗?像:

FILE* openCatalog(char catalogname[])
{
   FILE* file = fopen (catalogname, "r");