我正在尝试从控制台读取后打印特别大的值。当我尝试从两种不同的方式打印它时,一种是在分配之后,一种是来自strtol
函数的返回值,我得到不同的输出!有人可以解释一下为什么我注意到两种不同的输出吗?
输入值为:4294967290
以下是代码段。
long int test2 = strtol(argv[1], &string, 10);
printf("the strtol value is %ld\n", test2);
printf("the strtol function value is %ld\n", strtol(argv[1], &string, 10));
输出
the strtol value is -6
the strtol function value is 4294967290
答案 0 :(得分:2)
你需要做两件事:
在程序开头添加行#include <stdlib.h>
。这将导致strtol
被声明。 (您还需要#include <stdio.h>
才能声明printf
。)
将-Wall
添加到编译器标志中(如果您使用的是gcc或clang)。这将导致编译器告诉您需要声明strtol
,它甚至可能会建议要包含哪个标头。
发生的事情是你没有声明strtol
,结果是编译器假定它返回int
。
由于4294967290是2 32 -6,因此它是-6位的32位Two's-complement表示。因为编译器假定strtol
返回int
,所以它生成的代码只查看低位32位。由于您要将值赋给long
,因此编译器需要发出对int
进行符号扩展的代码。换句话说,它需要低位32位,就像它们是有符号整数(它将是-6)然后将-6加宽到long
。
在对printf
的第二次调用中,strtol
的返回值将插入printf
参数列表而不进行转换。您告诉printf
该参数是long
(通过使用l
中的%ld
标志),幸运的是整个64位都在参数列表中,因此{ {1}}将其作为printf
读出并打印“正确”值。
毋庸置疑,所有这些都是未定义的行为,您所看到的实际输出无法保证;它恰好与您的架构上的编译器一起工作。在其他一些编译器或其他架构上,事情可能完全不同,包括long
和int
的位长。因此,上述解释尽管可能有趣,但没有实际价值。如果您只是包含正确的标题,从而告诉编译器long
的实际返回类型,您将获得预期的输出。