0

私はファイルを開くことになっている関数を作成してきました(catalogname [])。ただし、コンパイルするたびに、理解できないこれら2つのエラーが発生します。

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

あなたが提供できる洞察を事前に感謝します。

4

5 に答える 5

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()固定名のファイルを開きますが、技術的には間違っていません。これを修正するには、引用符を削除する必要があります。は文字列ではなく文字を提供し、それがファイル名の最初の文字になります。だから、あまりにも削除します。*catalognamecatalogname**

  • これによりfopen()、値、実際には a を返すことになり、それをaFILE *に割り当てます。これは型の不一致であり、コンパイラが警告します。最初の書き換えで示したように、これを処理するより通常の方法は次のようになります。catalognamechar *

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

    これはあなたのエラーメッセージを説明します:

    a3.c:20: warning: assignment from incompatible pointer type
    
  • カタログがテキスト ファイルかバイナリ ファイルかはわかりません。それがバイナリ ファイルである"rb"場合、Windows を使用している場合 (実際に重要な場合) を使用して開く必要があり、Unix ライクなシステム (テキスト ファイルとバイナリ ファイルの区別がない場合) でも問題なく動作します。

  • コードの次の行は条件です。

    if (fopen != 0)
    

    これは、関数の関数ポインタfopen()が null かどうかを実際にチェックします。また、C 標準では、(使用している) ホストされた環境では、関数ポインターが null にならないことが保証されています。そのため、コンパイラはそのテストを最適化して、条件が常に真であると想定できます。

    実際に必要なのは、結果のテストです。

    if (fp != 0)
    
  • 次に、1 を返すステートメントと 0 を返すステートメントの 2 つの return ステートメントがあります。関数が a を返すように定義されておりFILE *、1 が整数であるため、1 を返すステートメントは、整数をポインターに変換することに関する警告を引き出します。

    これは、他の警告メッセージを説明します。

    a3.c:22: warning: return makes pointer from integer without a cast
    
  • 0 は null ポインター定数であり、このような関数が返す有効な値であるため、0 を返す return は警告を生成しません。

  • コードは、おそらく単に から値を返す必要がありますfopen()。この関数または呼び出し関数のいずれかで値をテストして、オープンが成功したことを確認するのは正しいことです。ここで次のようにテストできます。

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

    errnoandを使用するとstrerror()、ヘッダーも含める必要があることを意味します。

    #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.cstderr.hstd

于 2012-05-06T01:35:59.050 に答える
1
  • 互換性のないポインター型

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

    catalognameは文字の配列 ( )ですが、ファイル ポインタ ( )char catalogname[]を返します。当然のことながら、char 配列 (別の種類のポインターであり、さらに、割り当て不可) へのファイル ポインターの割り当ては意味がありません。fopen()FILE*

  • returnキャストなしで整数からポインターを作成します

    関数がここで返すことを宣言しますFILE*: FILE* openCatalog(...)。しかし、return ステートメントはreturn 1;andreturn 0;です。そこで、コンパイラは、値 1 (または 0) のファイル ポインターを返したいと考えているため、応答が返されます。

于 2012-05-06T01:33:53.467 に答える
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;
}
于 2012-05-06T01:36:40.230 に答える
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.
}
于 2012-05-06T01:34:15.523 に答える
0

最初の警告:

FILE*あなたは(何をfopen返すか) をcatalognamewhich isに代入していますchar []

2 番目の警告:

関数はFILE*、整数0または1

他に何か欲しかった?お気に入り:

FILE* openCatalog(char catalogname[])
{
   FILE* file = fopen (catalogname, "r");
于 2012-05-06T01:34:34.337 に答える