【问题标题】:Why does this code work on Linux but not on SunOS?为什么这段代码可以在 Linux 上运行,但不能在 SunOS 上运行?
【发布时间】:2013-05-23 18:47:01
【问题描述】:
#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:~>

【问题讨论】:

  • 仅供参考,设置 LC_ALL=C(或 en),或 Solaris 上的任何等效项,将为您提供英文信息...这在将它们粘贴到英文网站时很有帮助。
  • 处理共享库内部的方式不一样...
  • 实际上,如果他使用语言环境 el_GRko_KR 可能会更好,因为警告是红鲱鱼。
  • @Nick,关于更新,gcc --version 会很有帮助,因为 SunOS 5.10 于 2005 年 1 月发布,当时是 GCC 3.x 时代。尽管如此,gcc -Wall -Werror 非常擅长阻止愚蠢的 printf/scanf 错误。

标签: linux ubuntu solaris c sunos


【解决方案1】:

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

您还应该检查sscanf 的返回值。

【讨论】:

    【解决方案2】:

    您的编译器(在 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 语言和库的问题,您可能会更幸运地在 Stack Overflow 上搜索答案,而不是在这里。]

    编辑:另见msw's answer,它指出了另一个问题,至少与这个问题一样重要。

    【讨论】:

    • 我还注意到 Solaris 机器被报告为具有 SPARC cpu。 SPARC 和 x86 是不同的字节序,最终将 64 位值视为 32 位数字,幸运的是,其中一个选择正确的一半,另一个选择错误的一半。
    • @derobert - 我也几乎没有看到真正的错误,但这不是。
    【解决方案3】:

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

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

    编译没有错误并且可以工作。

    【讨论】:

    • 哇,是的,我错过了!该代码显然有足够的错误可以解决:-(
    • 感谢您让我回到这个问题,因为我在示例代码中看到了缓冲区溢出错误。 scanf 应该被弃用 ;)
    猜你喜欢
    • 2019-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    相关资源
    最近更新 更多