【问题标题】:strtoul giving unexpected outputstrtoul 给出意外的输出
【发布时间】:2025-11-24 21:55:02
【问题描述】:

我正在尝试使用strtoul 函数,但如下所示,它返回了一个意外的值(在开头添加了ff):

#include <stdio.h>
#include <string.h>
#include <limits.h>

main() {
    unsigned long temp ;
    char *err;
    temp = strtoul("3334444444",&err,10);
    if (temp > UINT_MAX) {
        printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
    }else 
        printf("%lx %x\n",temp,3334444444);
}

$./a.out
ffffffffc6bf959c c6bf959c ffffffff 

上面的输出对应于if 部分为真,尽管我希望else 部分在这里执行。谁能解释为什么strtoul 会这样?为什么它返回ffffffffc6bf959c 而不仅仅是c6bf959c?如果我在上面的代码中使用"333444444"(即少一个4)而不是"3334444444",那么我得到与else部分对应的正确输出(即13dff55c 13dff55c)。

Note : As pointed by melpomene in his reply below, stdlib.h header file should have been included and that will resolve the issue. Can anyone please let me know what is being done by the program by assuming the incorrect return type (int in this case) during compile time which can't be undone (or atleast it is not getting undone in this case) even after knowing the correct return type (unsigned long in this case) during link time ? In short, i want to know how c6bf959c is getting converted to ffffffffc6bf959c because of prototype not provided.

【问题讨论】:

  • 你试过用strtoull代替strtoul吗?
  • 我得到了您对这段代码的预期行为。你的环境是什么?
  • ULONG_MAX 与 32 位系统上的 UINT_MAX 大小相同。 strtoull 会更好,就像 brueg 说的那样。
  • 无符号长整数的最大值为 4294967295,因此您的 if 条件将为假(计算为零)。这可能取决于您的编译器和平台,我在 Windows 上使用了 Oepn Watcom。当传递一个大于 4294967295 的值时,我得到 FFFFFFFF。
  • 3334444444 可能是unsignedunsigned long 或者甚至可能是long(或其他类型)。所以"%x" 可能是个问题。推荐printf("%lx\n",3334444444UL);,避免不确定。

标签: c strtol


【解决方案1】:

使用 gcc 编译代码并启用警告会给出:

try.c:5:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 main() {
 ^~~~
try.c:5:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
try.c: In function ‘main’:
try.c:8:12: warning: implicit declaration of function ‘strtoul’ [-Wimplicit-function-declaration]
     temp = strtoul("3334444444",&err,10);
            ^~~~~~~
try.c:8:5: warning: nested extern declaration of ‘strtoul’ [-Wnested-externs]
     temp = strtoul("3334444444",&err,10);
     ^~~~
try.c:10:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
         printf("%lx %x %x\n",temp,3334444444,UINT_MAX);
                      ^
try.c:12:22: warning: format ‘%x’ expects argument of type ‘unsigned int’, but argument 3 has type ‘long long int’ [-Wformat=]
         printf("%lx %x\n",temp,3334444444);
                      ^

主要问题是implicit declaration of function ‘strtoul’,表示函数没有声明(因此假设返回int),因为你忘了#include &lt;stdlib.h&gt;。添加缺少的#include 修复了temp 的值。

但您还应该查看针对 printf 报告的警告并修复这些问题。

【讨论】:

  • 另外,temp &gt; UINT_MAX 在(普通)32 位系统上永远不会成立。
  • @melpomene :同意应该包含 stdlib.h 头文件。您能否通过在编译期间假设错误的返回值(在这种情况下为 int)来让我知道程序正在做什么,即使在知道之后也无法撤消(或至少在这种情况下不会撤消)链接期间正确的返回值(在这种情况下为无符号长)?
  • @yellowantphil :你能解释一下为什么它永远不会是真的吗? temp 是一个无符号长整数,可以大于 uint_max。 unsigned long 在 32 位系统上也可以是 8 个字节。对吧??
  • @zeebee 一个无符号长整数在 32 位系统上可能是 8 个字节,但通常是 4 个字节,所以你不能依赖 strtol 返回大于 UINT_MAX 的数字。出于这个原因,使用strtoll 会更安全。
  • @zeebee 在编译期间,会生成代码(基于对类型、使用的寄存器等的错误假设)。在链接时,什么都没有发生:符号引用被解析为库,但代码没有改变。特别是,链接器对类型(尤其是返回类型)一无所知。