我面临着c库函数strtoull的问题,它正在给我错误的输出。
int main(int argc, char *argv[])
{
unsigned long long int intValue;
if(atoi(argv[2]) == 1)
{
intValue = strtoull((const char *)argv[1], 0, 10 );
}
else
{
// ...
}
printf("intValue of %s is %llu \n", argv[1], intValue);
return 0;
}
我构建了它们并生成了32位和64位可执行文件,如str32_new和str64_new。 但是从32位exe接收的输出是错误的,因为返回了错误的数字:
strtoull应该为我传回的字符串“5368709120”返回号码5368709120,但它返回给我1073741824。
# ./str32_new "5368709120" 1
intValue of 5368709120 is 1073741824
我注意到当我从字符串中减少一个字符时,它会显示正确的输出。
# ./str32_new "536870912" 1
intValue of 536870912 is 536870912
附加到32位exe的glibc是
# readelf -Wa /home/str32_new | grep strt
[39] .shstrtab STRTAB 00000000 002545 000190 00 0 0 1
[41] .strtab STRTAB 00000000 0032f8 0002a4 00 0 0 1
0804a014 00000607 R_386_JUMP_SLOT 00000000 strtoull
6: 00000000 0 FUNC GLOBAL DEFAULT UND strtoull@GLIBC_2.0 (2)
55: 00000000 0 FILE LOCAL DEFAULT ABS strtoull.c
75: 00000000 0 FUNC GLOBAL DEFAULT UND strtoull@@GLIBC_2.0
77: 08048534 915 FUNC GLOBAL DEFAULT 15 my_strtoull
附加到64位exe的glibc是
# readelf -Wa /home/str64_new | grep strt
[39] .shstrtab STRTAB 0000000000000000 001893 000192 00 0 0 1
[41] .strtab STRTAB 0000000000000000 002cd0 00029b 00 0 0 1
0000000000601028 0000000700000007 R_X86_64_JUMP_SLOT 0000000000000000 strtoull + 0
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtoull@GLIBC_2.2.5 (2)
57: 0000000000000000 0 FILE LOCAL DEFAULT ABS strtoull.c
73: 00000000004006cc 804 FUNC GLOBAL DEFAULT 15 my_strtoull
82: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtoull@@GLIBC_2.2.5
64位exe显示正确的输出,但在某些系统上它也表现异常。 为什么32位exe中的strtoull表现如此以及如何解决这个问题?
答案 0 :(得分:2)
好的,所以我们已经确定这很明显是由于溢出而发生的,因为该值与如果转换为32位int时会发生的情况相匹配。
然而,这并没有解释所有内容 - 你确实使用了strtoull,而不是较短的strtoul,它确实适用于64位二进制文件。如果有的话,我很惊讶你甚至能够在你的32位版本中调用更长的版本(你是如何通过-m32?或者在特殊的机器上构建它的?)
This link,提出了一些可能导致strtoull被声明为int strtoll()
(可能是系统无法支持原始的lib版本)的联动现象,因此我们得到隐含的值的值通过int,在复制回你的unsigned long long之前。
无论哪种方式 - 这应该被编译器警告,尝试将其设置为c99并提高警告级别,也许这会让它大喊
答案 1 :(得分:1)
我认为那是因为溢出。 32位中的int
无法容纳一个大的数字(最大为4294967296
)。正如Leeor所说,5368709120 & (0xffffffff) = 1073741824
。
类型int
最小为32位宽,在大多数(如果不是全部)系统上仅为32位宽。
答案 2 :(得分:0)
您很可能忘记了#include <stdlib.h>
,并且可能未启用任何编译器警告(例如,使用未声明的函数)。
当C编译器看到对未声明函数的函数调用时,它会盲目地将int f(int)
作为原型。在您的情况下,strtoull()
的返回值将为int,因此该值将被截断为32位。
(在64位系统(通常int通常也只有32位)上获得正确的结果确实很奇怪。)