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 上没有这个文件,如果我更改为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

您的编译器(在 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在你的中使用printf,就像你在你的sscanf.

传递错误类型的参数是未定义的行为。在 Linux 上,它碰巧起作用了(这次);在 Solaris 上,它没有。

[你真的在问一个关于 C 语言和库的问题,你可能会更幸运地在 Stack Overflow 上搜索答案,而不是在这里。]

编辑:另请参阅msw 的答案,它指出了另一个问题,至少与这个问题一样重要。

于 2013-05-23T20:00:43.300 回答
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 回答