2

私のプログラムでは、 basename 関数を使用してパーティションを取得しています。まず、if 文を次のように書きます。

if (!strncmp(buf, 
    basename("/dev/mmcblk0p3"), 
    strlen(basename("/dev/mmcblk0p3"))) {
    ret = 1;
} else {
    ret = 0;
}

buf は文字列 "mmcblk0p3" を指していますが、ret = 0 で、gdb を使用すると、basename("/dev/mmcblk0p3") が奇妙な文字列を返すことがわかりましたが、プログラムを次のように変更したとき:

char *p = NULL;
p = basename("/dev/mmcblk0p3");
if (!strncmp(buf, p, strlen(p)) {
    ret = 1;
} else {
    ret = 0;
}

ret が 1 の場合、プログラムは正常に実行されます。違いはなんですか?basename はこのように使用できませんか? コンパイル環境はarmel7v/gccです。

4

2 に答える 2

3

従来の (POSIX)basename()関数、その入力文字列を変更する場合があります。

あなたのバージョン入力を変更しているようです.

basename()さらに悪いことに、文字列リテラルを変更することで、未定義の動作も呼び出しています。

于 2013-05-21T08:48:39.130 に答える
1

文字列を返す非再入可能関数 basename を使用した結果の 1 つは、後続の呼び出しで以前の結果が無効になることです。2 番目の呼び出しを行う前に戻り値のコピーを作成するか、2 番目の呼び出しが返された後に古い値の使用を停止する必要があります。これは、basename がその結果を格納するための内部バッファを 1 つしか持たないためです。これは、パラメータを変更しないと仮定した場合です (文字列リテラルでクラッシュしないため、プログラムに当てはまるように見えますが、未定義の動作です)。

プログラムを移植可能にするには、次のように変更します。

char *p = NULL;
char pathname[] = "/dev/mmcblk0p3";
p = basename(pathname);
if (!strncmp(buf, p, strlen(p)) {
    ret = 1;
} else {
    ret = 0;
}
于 2013-05-21T09:03:02.860 に答える