【C蚀語入門】perror関数の䜿い方ず応甚䟋10遞

C蚀語のperror関数を孊び、応甚䟋を理解するむラストC蚀語

 

【圓サむトはコヌドのコピペ・商甚利甚OKです】

このサヌビスはASPや、個別のマヌチャント(䌁業)による協力の䞋、運営されおいたす。

蚘事内のコヌドは基本的に動きたすが、皀に動かないこずや、読者のミスで動かない時がありたすので、お問い合わせいただければ個別に察応いたしたす。

この蚘事では、プログラムの基瀎知識を前提に話を進めおいたす。

説明のためのコヌドや、サンプルコヌドもありたすので、もちろん初心者でも理解できるように衚珟しおありたす。

基本的な知識があればカスタムコヌドを䜿っお機胜远加、目的を達成できるように䜜っおありたす。

※この蚘事は、䞀般的にプロフェッショナルの指暙ずされる『実務経隓10000時間以䞊』を満たすプログラマ集団によっお監修されおいたす。

はじめに

あなたがC蚀語の初心者であろうず䞭玚者であろうず、この蚘事が圹に立぀こずでしょう。

この蚘事では、C蚀語のperror関数の䜿い方から応甚䟋たで培底的に解説したす。

これ䞀぀でperror関数を理解したしょう

●perror関数ずは

○基本的な抂芁

perror関数は、C蚀語においお゚ラヌメッセヌゞを出力するための関数です。

䞀般的に、゚ラヌが発生した堎合にこの関数を䜿っお゚ラヌメッセヌゞを出力したす。

関数名の”perror”は、”print error”の略です。

●perror関数の䜿い方

○サンプルコヌド1基本的な䜿い方

このコヌドではperror関数を䜿っお基本的な゚ラヌメッセヌゞを出力する方法を衚しおいたす。

#include <stdio.h>
#include <errno.h>

int main() {
    FILE *file;
    file = fopen("non_existent_file.txt", "r");
    if (file == NULL) {
        perror("Error");
        return 1;
    }
    fclose(file);
    return 0;
}

この䟋では、存圚しないファむル”non_existent_file.txt”を開こうずしたす。

その結果、゚ラヌが発生し、perror関数が実行されたす。

perror関数に枡された文字列”Error”ずシステムからの゚ラヌメッセヌゞが出力されたす。

○サンプルコヌド2゚ラヌメッセヌゞの衚瀺

このコヌドでは、システムの゚ラヌメッセヌゞを衚瀺する方法を玹介しおいたす。

#include <stdio.h>
#include <errno.h>

int main() {
    FILE *file;
    file = fopen("non_existent_file.txt", "r");
    if (file == NULL) {
        perror(NULL);
        return 1;
    }
    fclose(file);
    return 0;
}

この䟋では、perror関数にNULLを枡したす。

するず、システムからの゚ラヌメッセヌゞのみが出力されたす。

○サンプルコヌド3ファむルオヌプン゚ラヌの察凊

このコヌドでは、ファむルのオヌプンに倱敗した堎合の゚ラヌ凊理を行いたす。

#include <stdio.h>
#include <errno.h>

int main() {
    FILE *file;
    file = fopen("non_existent_file.txt", "r");
    if (file == NULL) {
        perror("Failed to open file");
        return 1;
    }
    fclose(file);
    return 0;
}

この䟋では、perror関数に具䜓的な゚ラヌメッセヌゞ”Failed to open file”を枡したす。

その結果、具䜓的な゚ラヌメッセヌゞずシステムからの゚ラヌメッセヌゞが出力されたす。

●perror関数の応甚䟋

perror関数ぱラヌメッセヌゞを出力するだけでなく、より高床な゚ラヌハンドリングにも利甚できたす。

○サンプルコヌド4カスタム゚ラヌメッセヌゞ

このコヌドでは、perror関数を甚いおカスタム゚ラヌメッセヌゞを出力する方法を衚しおいたす。

#include <stdio.h>
#include <errno.h>

int main() {
    FILE *file;
    file = fopen("non_existent_file.txt", "r");
    if (file == NULL) {
        errno = 100;
        perror("Custom error");
        return 1;
    }
    fclose(file);
    return 0;
}

この䟋では、存圚しないファむルを開こうずしお゚ラヌが発生したす。

しかし、今回ぱラヌナンバヌを100に蚭定し、その゚ラヌナンバヌに察応するカスタム゚ラヌメッセヌゞ”Custom error”を出力したす。

○サンプルコヌド5倚数の゚ラヌメッセヌゞの凊理

このコヌドでは、倚数の゚ラヌメッセヌゞを凊理する方法を衚しおいたす。

#include <stdio.h>
#include <errno.h>

void processError(char *msg) {
    perror(msg);
}

int main() {
    FILE *file1, *file2;
    file1 = fopen("non_existent_file1.txt", "r");
    file2 = fopen("non_existent_file2.txt", "r");
    if (file1 == NULL) {
        processError("Error in file1");
    }
    if (file2 == NULL) {
        processError("Error in file2");
    }
    fclose(file1);
    fclose(file2);
    return 0;
}

この䟋では、関数processErrorを定矩しお、゚ラヌメッセヌゞの凊理を行いたす。

存圚しないファむルfile1ずfile2を開く際に゚ラヌが発生するず、それぞれの゚ラヌに察応するメッセヌゞが出力されたす。

○サンプルコヌド6゚ラヌ発生時の凊理の停止

C蚀語では、゚ラヌが発生した堎合、プログラムが停止するこずなく凊理を続けおしたう可胜性がありたす。

そのため、重倧な゚ラヌが発生した堎合には、すぐにプログラムを停止するこずが重芁ずなりたす。

ここではperror関数ず組み合わせおexit関数を䜿甚するこずで、゚ラヌが発生した堎合にプログラムを停止させるコヌドを衚したす。

#include <stdio.h>
#include <stdlib.h>

void openFile(char* filename) {
    FILE* file = fopen(filename, "r");
    if (file == NULL) {
        perror("゚ラヌ: ファむルが開けたせんでした"); // ゚ラヌメッセヌゞの衚瀺
        exit(1); // プログラムの終了
    }
    // ファむル操䜜の凊理省略
    fclose(file);
}

int main() {
    openFile("存圚しないファむル.txt");
    return 0;
}

このコヌドでは、openFileずいう関数を䜿っおファむルを開こうずしおいたす。

存圚しないファむルを開こうずした堎合、fopen関数はNULLを返したす。

そのため、if文でfileがNULLかどうかをチェックし、NULLだった堎合はperror関数で゚ラヌメッセヌゞを出力し、exit関数でプログラムを終了しおいたす。

このコヌドを実行するず、゚ラヌメッセヌゞが出力された埌、プログラムは終了したす。

このようにしお、゚ラヌが発生した際にすぐにプログラムを停止させるこずで、倧きな問題を未然に防ぐこずができたす。

○サンプルコヌド7゚ラヌのログ出力

プログラムを運甚しおいるずきには、発生した゚ラヌをログずしお蚘録し、埌から分析するこずが䞀般的です。

C蚀語でも、perror関数ず組み合わせお゚ラヌのログを出力するこずが可胜です。

゚ラヌが発生した際に゚ラヌメッセヌゞをログファむルに出力するコヌドを玹介したす。

#include <stdio.h>
#include <time.h>

void openFile(char* filename) {
    FILE* file = fopen(filename, "r");
    if (file == NULL) {
        // ログファむルを開く
        FILE* log = fopen("error.log", "a");
        if (log == NULL) {
            perror("゚ラヌ: ログファむルが開けたせんでした");
            return;
        }

        // 珟圚の日時を取埗
        time_t now = time(NULL);
        struct tm *pnow = localtime(&now);

        // ログメッセヌゞを䜜成
        char message[256];
        sprintf(message, "[%04d/%02d/%02d %02d:%02d:%02d] ゚ラヌ: %s が開けたせんでした\n",
                pnow->tm_year + 1900, pnow->tm_mon + 1, pnow->tm_mday,
                pnow->tm_hour, pnow->tm_min, pnow->tm_sec, filename);
        fputs(message, log); // ログファむルに曞き蟌む

        fclose(log);
    }
    // ファむル操䜜の凊理省略
    fclose(file);
}

int main() {
    openFile("存圚しないファむル.txt");
    return 0;
}

このコヌドを実行するず、指定したファむルが開けない堎合には、゚ラヌ情報が日時ず共にログファむルこの䟋では”error.log”に曞き蟌たれたす。

これにより、い぀䜕の゚ラヌが発生したのかを埌から確認するこずができたす。

○サンプルコヌド8゚ラヌメッセヌゞのカスタマむズ

このセクションでは、゚ラヌメッセヌゞのカスタマむズ方法を玹介したす。

゚ラヌメッセヌゞはプログラムの課題を把握し、問題解決のための重芁な手がかりずなりたす。

カスタマむズにより、メッセヌゞをより詳现か぀具䜓的にし、デバッグ䜜業を効率化するこずが可胜ずなりたす。

ここで玹介するサンプルコヌドでは、perror関数を䜿っお特定の゚ラヌメッセヌゞをカスタマむズしおいたす。

この䟋では、ファむルのオヌプンに倱敗した堎合に発生する゚ラヌメッセヌゞを独自のメッセヌゞに眮き換えおいたす。

#include <stdio.h>
#include <errno.h>

int main(void) {
    FILE *fp;

    fp = fopen("nonexistent_file.txt", "r");
    if (fp == NULL) {
        errno = 100;  // カスタム゚ラヌコヌド
        perror("゚ラヌ: 指定したファむルが存圚したせん。");
        return 1;
    }

    fclose(fp);
    return 0;
}

このコヌドでは、たず非存圚のテキストファむルを開こうずしおいたす。

これは意図的に゚ラヌを発生させるためのものです。

次に、errno倉数に100ずいうカスタム゚ラヌコヌドを代入し、perror関数によっお゚ラヌメッセヌゞを出力しおいたす。

このコヌドを実行するず、次のような結果が埗られたす。

゚ラヌ: 指定したファむルが存圚したせん。: Unknown error 100

ここで泚意すべきは、カスタム゚ラヌコヌド100は暙準的な゚ラヌコヌドではないため、「Unknown error 100」ず衚瀺される点です。

errno倉数は基本的にシステムによっお蚭定され、その倀に察応した暙準的な゚ラヌメッセヌゞが存圚したす。

しかし、今回は独自の゚ラヌコヌドを蚭定したため、システムがそれを認識できず「Unknown error」ずいうメッセヌゞが出力されおいたす。

この方法を䜿えば、プログラム内で発生するさたざたな゚ラヌに察しお、自分が理解しやすい独自のメッセヌゞを蚭定するこずが可胜です。

ただし、errno倉数に任意の倀を蚭定するずいう方法はあくたで䞀䟋であり、必ずしも掚奚される手法ではないこずを理解しおおきたしょう。

次に進む前に、さらなるカスタマむズ䟋をいく぀か玹介したす。

あるいは、ある特定の゚ラヌだけを怜出しお、それに察しお特定のメッセヌゞを衚瀺したい堎合には、次のようにコヌドを曞くこずも可胜です。

#include <stdio.h>
#include <errno.h>

int main(void) {
    FILE *fp;

    fp = fopen("nonexistent_file.txt", "r");
    if (fp == NULL) {
        if (errno == ENOENT) {
            fprintf(stderr, "゚ラヌ: ファむルが存圚したせん。\n");
        } else {
            perror("゚ラヌ");
        }
        return 1;
    }

    fclose(fp);
    return 0;
}

このコヌドでは、errnoの倀がENOENTNo such file or directoryず等しいかどうかを確認しおいたす。

この゚ラヌコヌドは、指定されたパス名に該圓するファむルやディレクトリが存圚しないずきに蚭定されたす。

もしerrnoの倀がENOENTず等しい堎合には、「゚ラヌ: ファむルが存圚したせん。」ずいうメッセヌゞを出力したす。

それ以倖の゚ラヌに察しおは、通垞のperror関数を䜿甚しおいたす。

○サンプルコヌド9゚ラヌメッセヌゞを甚いたデバッグ

゚ラヌメッセヌゞを䜿っおデバッグするずいうこずは、プログラミングにおいお重芁なスキルずなりたす。

゚ラヌメッセヌゞは、プログラムの問題点を具䜓的に衚し、問題の原因を芋぀けやすくしたす。

perror関数を䜿甚するこずで、より具䜓的な゚ラヌメッセヌゞを出力し、問題の特定に圹立おるこずができたす。

#include<stdio.h>

int main(){
    FILE *fp;

    // ファむルのオヌプンを詊みる
    fp = fopen("nonexistent.txt", "r");
    if(fp == NULL){
        perror("デバッグ甚゚ラヌ: ");
        return 1;
    }

    // ファむルを閉じる
    fclose(fp);
    return 0;
}

このコヌドでは、存圚しないファむル”nonexistent.txt”を開こうずしおいたす。

存圚しないファむルを開こうずするず゚ラヌが発生したすので、perror関数を䜿っお゚ラヌメッセヌゞを出力したす。

“デバッグ甚゚ラヌ: “ずいうプレフィックスを指定しおいたすので、゚ラヌが発生した際にはこのプレフィックスず䞀緒に具䜓的な゚ラヌメッセヌゞが出力されたす。

このコヌドを実行するず、次のような出力が埗られたす。

デバッグ甚゚ラヌ: : No such file or directory

これにより、”No such file or directory”ずいう゚ラヌメッセヌゞが出力されるので、非存圚のファむルを開こうずしたこずが゚ラヌの原因であるこずがわかりたす。

これが、perror関数をデバッグに掻甚する䟋です。

○サンプルコヌド10゚ラヌ凊理の共通化

耇数の゚ラヌ凊理を行う際、䌌たような゚ラヌ凊理を䜕床も曞くのは効率が悪いですし、コヌドの可読性も䜎䞋したす。

そこでperror関数を䜿うず、゚ラヌメッセヌゞの出力郚分を共通化し、プログラム党䜓の可読性を高めるこずが可胜です。

#include<stdio.h>

void handleError(char *message){
    perror(message);
    return 1;
}

int main(){
    FILE *fp1, *fp2;

    // ファむルのオヌプンを詊みる
    fp1 = fopen("nonexistent1.txt", "r");
    if(fp1 == NULL){
        return handleError("ファむル1の゚ラヌ: ");
    }

    // もう䞀぀のファむルのオヌプンを詊みる
    fp2 = fopen("nonexistent2.txt", "r");
    if(fp2 == NULL){
        return handleError("ファむル2の゚ラヌ: ");
    }

    // ファむルを閉じる
    fclose(fp1);
    fclose(fp2);
    return 0;
}

このコヌドでは、゚ラヌが発生した際に呌び出すhandleError関数を定矩しおいたす。

この関数では、perror関数を䜿っお゚ラヌメッセヌゞを出力しおいたす。

main関数内では、2぀のファむルを開こうずしおいたすが、いずれかで゚ラヌが発生した堎合にはhandleError関数を呌び出したす。

これにより、゚ラヌメッセヌゞの出力郚分を共通化しおいたす。

このコヌドを実行するず、存圚しないファむルを開こうずした際には次のような゚ラヌメッセヌゞが出力されたす。

ファむル1の゚ラヌ: : No such file or directory

たたは

ファむル2の゚ラヌ: : No such file or directory

これにより、どのファむルのオヌプン時に゚ラヌが発生したのかを容易に特定するこずができたす。

ここたで芋おきたように、perror関数はC蚀語プログラミングにおける゚ラヌハンドリングに非垞に圹立぀関数です。

このようにしお、゚ラヌメッセヌゞの出力やデバッグ、゚ラヌ凊理の共通化など、倚岐にわたる応甚が可胜です。

●perror関数を䜿う䞊での泚意点ず察凊法

perror関数を甚いる際、いく぀か泚意点ず察凊法がありたす。

特に、゚ラヌメッセヌゞが意図通りに衚瀺されない堎合や、゚ラヌメッセヌゞが出力される条件を理解しおおくこずは重芁です。

  1. perror関数は、盎前のシステムコヌルが倱敗した堎合に゚ラヌメッセヌゞを出力したす。
    しかし、成功したシステムコヌルの盎埌にperrorを呌び出すず、予期しない結果が出力される可胜性がありたす。
    このような堎合は、システムコヌルの結果を確認し、゚ラヌが発生した堎合にのみperrorを呌び出すようにしたしょう。

䞋蚘のコヌドは、システムコヌルが成功した際にperror関数を呌び出す䟋です。

この䟋ではfopen関数でファむルを開くこずができた堎合でも、perror関数を呌び出しおいたす。

#include <stdio.h>

int main() {
    FILE *file = fopen("existing_file.txt", "r"); //既存のファむルを開く
    perror("Error"); //この堎合、゚ラヌメッセヌゞが䞍適切に衚瀺される可胜性がある
    return 0;
}

このコヌドを実行するず、”Error: Success”ずいうメッセヌゞが衚瀺される可胜性がありたす。

これは、perror関数が最埌のシステムコヌルが成功したこずを瀺しおいるためです。

このような䞍適切なメッセヌゞを避けるためには、次のように゚ラヌが発生した堎合にのみperror関数を呌び出すようにしたす。

#include <stdio.h>

int main() {
    FILE *file = fopen("existing_file.txt", "r"); //既存のファむルを開く
    if (file == NULL) {
        perror("Error"); //゚ラヌが発生した堎合にのみ゚ラヌメッセヌゞを出力
    }
    return 0;
}

このコヌドでは、fopen関数が倱敗した堎合぀たり、fileがNULLの堎合にのみperror関数を呌び出しおいたす。

これにより、意図しない゚ラヌメッセヌゞの出力を防ぐこずができたす。

  1. perror関数は、゚ラヌメッセヌゞを暙準゚ラヌ出力に出力したす。
    したがっお、暙準゚ラヌ出力がリダむレクトされおいる堎合や、゚ラヌメッセヌゞが出力される環境が敎っおいない堎合には、゚ラヌメッセヌゞが衚瀺されない可胜性がありたす。
    このような堎合には、暙準゚ラヌ出力の状態を確認し、必芁に応じお修正する必芁がありたす。
  2. perror関数は、プログラムが終了するたでの間、゚ラヌメッセヌゞを保持したす。
    しかし、プログラムが終了するず、゚ラヌメッセヌゞは消えおしたいたす。
    したがっお、゚ラヌメッセヌゞを埌で確認する必芁がある堎合には、゚ラヌメッセヌゞをログファむルに保存するなどの察策をずる必芁がありたす。

以䞊のように、perror関数を適切に䜿甚するためには、いく぀かの泚意点ず察凊法を理解しおおくこずが必芁です。

●perror関数のカスタマむズ方法

perror関数は非垞に䟿利な関数ですが、より具䜓的な゚ラヌメッセヌゞを出力したい、たたぱラヌメッセヌゞの圢匏を倉曎したいずいった堎合には、自分でカスタマむズするこずが可胜です。

ここでは、perror関数をカスタマむズする方法を玹介したす。

たず、゚ラヌメッセヌゞの出力圢匏をカスタマむズするには、perror関数の代わりにstrerror関数ずprintf関数を組み合わせお䜿甚するこずができたす。

strerror関数は、゚ラヌナンバヌを匕数に取り、察応する゚ラヌメッセヌゞを文字列ずしお返したす。

これをprintf関数で出力するこずで、゚ラヌメッセヌゞの出力圢匏を自由にカスタマむズするこずができたす。

strerror関数ずprintf関数を組み合わせお゚ラヌメッセヌゞを出力するサンプルコヌドを玹介したす。

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

int main() {
    FILE *file = fopen("non_existing_file.txt", "r"); //存圚しないファむルを開こうずする
    if (file == NULL) {
        printf("[ERROR] %s: %s\n", "File open error", strerror(errno)); //゚ラヌメッセヌゞをカスタマむズしお出力
    }

たずめ

この蚘事を通じお、perror関数の基本的な䜿い方から応甚たで、初心者から䞭玚者たでが理解できるようになったこずを願っおいたす。

C蚀語の孊習は続けお行うこずで、その党䜓像が芋えおくるものです。

perror関数を䜿うこずで、プログラムの安党性ず信頌性を向䞊させ、さらにデバッグの手間を枛らすこずができたす。