学習記録

たまには誰かの役にたったらいいな

C言語IDEのCLionでファイルの読み込みをしようとしても読み込めない件

問題

CLionでファイルの読み込みをしようとしても読み込めない件について
CLionのファイルパスはどうなっているか?

その前にCLionとは

JetBrains社の C と C++用のIDEである。公式サイト
学生だと「Free individual licenses for students and faculty members」から無料で使えるのでおすすめ。
f:id:sikeda107:20180926004454p:plain

問題のプロジェクト

プロジェクトのファイル構成は下記のような感じ。
f:id:sikeda107:20180926003622p:plain
main.c の中身は下記のもの。

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

void test() {
    FILE *fp;
    char *filename = "./hello.txt";
    char ch;

//    File Read
    fp = fopen(filename, "r");
    if (fp == NULL) {
        fprintf(stderr, "Cannot file open %s\n", filename);
        exit(1);
    }

    while ((ch = fgetc(fp)) != EOF) {
        putchar(ch);
    }
    fclose(fp);
}

int main() {
    test();
    return 0;
}

hello.txtの中身は下記のもの

Hello World

main.chello.txtを読み込んで、一文字ずつ標準出力するプログラムである。想定する実行結果は「Hello World」の出力である。 しかし、結果は下記のようにファイルの読み込みが失敗している。

/Users/******/CLionProjects/HELLO/cmake-build-debug/HELLO
Cannot file open ./hello.txt

Process finished with exit code 1

解決策

hello.txtcmake-build-debugディレクトリの下に入れればいい。そうすると下記のような構成になる。

$ ls cmake-build-debug/
CMakeCache.txt          HELLO.cbp               hello.txt
CMakeFiles              Makefile
HELLO                   cmake_install.cmake

下記実行結果

/Users/*****/CLionProjects/HELLO/cmake-build-debug/HELLO
Hello World

Process finished with exit code 0

きちんとファイルの中身が出力されている。

原因

そもそも./hello.txt./カレントディレクトリがどこをさしているのか。main.cと同じ階層(/Users/*****/CLionProjects/HELLO/)をさしていると思っていたがどうやら違うらしい。確認のため下記関数を定義し、実行してみる。

void test2(){
    printf("> pwd \n");
    system("pwd");
    printf("> ls \n");
    system("ls");
}
  • system();は渡した文字列をターミナルに渡してくれる関数(参考)で、
  • pwdはカレントディレクトリのフルパスを出力するUNIXコマンド
  • lsディレクトリ内のファイルの一覧を表示するUNIXコマンド
    である。Windowsだとdirで代用がきくと思う。

実行結果は

/Users/sikeda/CLionProjects/HELLO/cmake-build-debug/HELLO
> pwd 
/Users/sikeda/CLionProjects/HELLO/cmake-build-debug
> ls 
CMakeCache.txt      HELLO.cbp       hello.txt
CMakeFiles      Makefile        
HELLO           cmake_install.cmake

Process finished with exit code 0

cmake-build-debugがカレントディレクトリであることが確認できる。よくよく考えると、実行ファイルであるHELLOcmake-build-debugにあるので当然である…。
試しにターミナルを開いて、直接実行ファイルを実行してみると、同じ結果が得られる。

$ pwd
/Users/****/CLionProjects/HELLO/cmake-build-debug
$ ./HELLO
> pwd 
/Users/****/CLionProjects/HELLO/cmake-build-debug
> ls 
CMakeCache.txt          HELLO.cbp               hello.txt
CMakeFiles              Makefile
HELLO                   cmake_install.cmake

余談

ビルド先のディレクトリを変更できるらしい。

Q: CLionのビルド出力パスは変更できますか? A: 以下のようにCMake変数を指定すれば簡単に変更できます: set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "my_dir") 参考

  1. CMakeLists.txtset(CMAKE_RUNTIME_OUTPUT_DIRECTORY "my_dir")を追記する。
  2. CMake project needs to be reloardedと出るので、Reload changesをクリックする。
  3. その後、実行するとmy_dirが作られ、そこに実行ファイルが生成される。 下記は実行結果
/Users/****/CLionProjects/HELLO/cmake-build-debug/my_dir/HELLO
> pwd 
/Users/****/CLionProjects/HELLO/cmake-build-debug/my_dir
> ls 
HELLO

Process finished with exit code 0

HELLO.cbpの中身を見てみると、中身が変更されているのがわかる。.cbpはおそらくCode::Blocks Project Fileのこと。このファイルはプログラムのビルド方法を決めるxmlファイルである。参考 What is the difference between a cbp file and a cpp file?

変更前:
<Target title="HELLO">
    <Option output="/Users/****/CLionProjects/HELLO/cmake-build-debug/HELLO" prefix_auto="0" extension_auto="0"/>
    <Option working_dir="/Users/****/CLionProjects/HELLO/cmake-build-debug"/>
    
    と
<Target title="HELLO/fast">
    <Option output="/Users/****/CLionProjects/HELLO/cmake-build-debug/HELLO" prefix_auto="0" extension_auto="0"/>
    <Option working_dir="/Users/****/CLionProjects/HELLO/cmake-build-debug"/>

変更後:
<Target title="HELLO">
    <Option output="/Users/****/CLionProjects/HELLO/cmake-build-debug/my_dir/HELLO" prefix_auto="0" extension_auto="0"/>
    <Option working_dir="my_dir"/>
と
<Target title="HELLO/fast">
    <Option output="/Users/****/CLionProjects/HELLO/cmake-build-debug/my_dir/HELLO" prefix_auto="0" extension_auto="0"/>
    <Option working_dir="my_dir"/>

最後に

CLionでファイルの入出力を扱うときに絶対パスで指定していたのを、相対パスに変更できるのでとても楽になる。