2
#include <stdio.h>

int main() {
  char *str = "11111111-22222222 r-xp 00000000 00:0e 1843624    /lib/libdl.so.0";
  unsigned long long start_addr, stop_addr, offset;
  char* access = NULL;
  char* filename = NULL;
  sscanf(str, "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms",
           &start_addr, &stop_addr, &access, &offset, &filename);

  printf("\n start : %x, stop : %x, offset : %x\n",start_addr,stop_addr,offset);
  printf("\n Permission : %s\n",access);
  printf("\n Filename : %s\n",filename);
    return 0;
}

Linux では正しい出力が得られますが、Solaris ではファイルは libdl.so と呼ばれます (Solaris には libdl.so.0 はありません)。 Solaris インストールのファイル名 (libdl.so) を変更すると、セグメンテーション違反が発生します。

$ cc Cperm.c ;./a.out 
Cperm.c: I funktion "main":
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 3 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 4 har typen "long long unsigned int" [-Wformat]

 start : 11111111, stop : 22222222, offset : 0

 Permission : r-xp

 Filename : /lib/libdl.so.0

上記はubuntuでのもので、Solarisでは警告なしでコンパイルされますが、セグメンテーション違反が生成されます。

uname -a
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
my:~>cc Cperm.c;./a.out 

 start : 0, stop : 11111111, offset : 0
Segmentation fault

アップデート

my:~>uname -a;gcc -Wall Cperm.c
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
Cperm.c: In function `main':
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: long long unsigned int format, pointer arg (arg 5)
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: too many arguments for format
Cperm.c:11: warning: unsigned int format, different type arg (arg 2)
Cperm.c:11: warning: unsigned int format, different type arg (arg 3)
Cperm.c:11: warning: unsigned int format, different type arg (arg 4)
my:~>gcc Cperm.c
my:~>
4

3 に答える 3

11

Solaris 10sscanfのマニュアル ページを確認してください。%m修飾子はそこでサポートされていません。

の戻り値も確認する必要がありますsscanf

于 2013-05-23T20:35:51.590 に答える
4

実際には、見た目よりもはるかに簡単です。あなたのコードは、文字列の結果を格納するためのスペースを割り当てていません。この短いコードには同じ欠陥があります。

#include <stdio.h>
int main() {
    char *word = NULL;
    sscanf("hello world", "%s", &word); 
    printf("%s\n", *word);
    return 0;
}

あるコンパイラでは「動作」するが別のコンパイラでは動作しない理由は、ストレージの割り当て方法に関係している可能性があります。そのコードによって生成されたエラーは次のとおりです。

cperm.c:5:5: error: format ‘%s’ expects argument of type ‘char *’, 
             but argument 3 has type ‘char **’

これは恐ろしいことではありませんが、実際には致命的です。-Werror オプションを指定して gcc を実行すると、その警告によりコンパイルが停止し、a.out. word適切な定義と使用

char word[64];
sscanf("hello world", "%63s", word); 
printf("%s\n", word);

エラーなしでコンパイルされ、動作します。

于 2013-05-24T04:15:44.717 に答える
4

あなたのコンパイラ(Ubuntu、および警告を有効にした場合はおそらくSolaris)は、何が悪いのかを教えてくれました:

Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
⋮

で行ったのと同じように、 で使用%llxする必要があります。printfsscanf

間違った型の引数を渡すと、未定義の動作になります。Linuxでは、たまたま機能しました(今回)。Solaris ではそうではありませんでした。

[あなたは本当に C 言語とライブラリについて質問しています。ここではなく、スタック オーバーフローで回答を検索したほうがよいでしょう。]

編集: msw's answerも参照してください。これは、少なくともこれと同じくらい重要な別の問題を指摘しています。

于 2013-05-23T20:00:43.300 に答える