😊

Cのdirnameについて

2021/12/18に公開

C言語のdirnameやbasenameは与える引数を破壊するみたいです。

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

int main(int argc, char** argv) 
{
    if(argc == 2) {
       char* dir_name = dirname(argv[1]);
       puts(argv[1]);
       puts(dir_name);
    }
    
    exit(0);
}

これは期待通りの値を表示しません。
中身を考えるとdirnameの戻り値はヒープに確保するのではなく引数のスタックを使っている
みたいです。
正しくは

#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>
#include <limits.h>
#incldue <string.h>

int main(int argc, char** argv) 
{
    if(argc == 2) {
       char fname[PATH_MAX];
       strncpy(fname, argv[1], PATH_MAX);
       char* dir_name = dirname(fname);
       puts(argv[1]);
       puts(dir_name);
    }
    
    exit(0);
}

なはずです。確認してませんが。つまりdirnameの戻り値は引数のスタックのメモリを使っているということです。メモリはどこかに確保しないといけないため、ヒープを使うか、スタックのメモリを使うかしかありませんが、スタックのメモリを使っているみたいです。その代わり戻り値をfreeする必要がないです。

拙作のコンパイラでは以下のように回避しました。

#include <neo-c2.h>

int main(int argc, char** argv) 
{
    if(argc == 2) {
       char* dir_name = dirname(string(argv[1]));
       puts(argv[1]);
       puts(dir_name);
    }
    
    exit(0);
}

stringでヒープにメモリを確保してます。BoehmGCが管理するヒープです。

Discussion