为什么这个代码在Linux上工作,而不是在SunOS上工作?

#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:~> 

检查Solaris 10 sscanf的手册页。 这里不支持%m修饰符。

你也应该检查sscanf的返回值。

你的编译器(在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] ⋮ 

你需要在你的printf使用%llx ,就像你在sscanf

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

[你真的在问C语言和库的问题,你可能有更好的运气搜索堆栈溢出的答案,而不是在这里。]

编辑:另见msw的答案 ,指出另外一个问题,至少和这个一样重要。

它实际上比它看起来更简单。 您的代码从未分配空间来存储字符串结果。 这个较短的代码有相同的缺陷:

 #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); 

编译没有错误,工作。