什么时候限制整数宽度?
When is the integer width restricted?
我在编写一个要求用户输入值 N 然后输出结果 5^N 的程序时遇到了问题。问题是,如果用户输入的数字大于 (2^31)-1,他们的数字就会溢出,程序会给他们一个错误的答案。
我所做的是将用户给出的整数值赋给一个无符号长整数值。这样如果程序可以检查是否输入了大于 (2^31)-1 的数字,因为 unsigned long 可以容纳比 signed int 多得多的正整数。这样做会使程序正常运行,因为我可以检查是否发生了溢出。
然而我的问题是:当用户输入一个大于 2^31 - 1 的值到原始有符号整数变量(这应该会导致它溢出)时,为什么我可以分配这个溢出的值进入无符号并得到 "correct" 数字是什么?仅在尝试对该数字进行操作时才会发生溢出吗?内存是否存储实际数字(不受位宽限制)?
int endCount;
unsigned long endCountUn; /* power N */
/* Read value of N */
printf("This program will compute 5^N; enter N: ");
scanf("%d", &endCount);
/*
User's value put into unsigned long. Helps with detecting overflow.
*/
endCountUn = endCount;
if ( (endCount < 0) && (endCountUn < 2147483648) )
{
printf("The operation is undefined for negative integers\n");
}
else if ( endCountUn > 2147483647 )
{
printf("The value exceeds the supported numerical range\n");
}
if ( (endCount < 0) && (endCountUn < 2147483648) )
对满足两个条件的数字n执行此if块。
endCount
,是一个(32 位)有符号整数,以 2 的补码表示。
因此,表达式的第一项选择设置了高位的所有 n:
范围 1:[0x80000000...0xFFFFFFFF]
第二项选择范围
内的所有n
范围 2:[0x00000000..0x7FFFFFFF]。
两个范围内的 n 的集合是空集。
因此,您上面的 if 主体将永远不会被执行。
第二个 if(else if 部分)要求范围 1 中的值。
因此,您的测试代码可以简化为:
if( endCount < 0 ) { printf("Value out of range"); }
因为,无论用户输入什么(负数或范围 1 中的值),endCount 始终为负数。
最后,如果您只想允许无符号整数值,为什么首先使用 scanf("%d",endCount)
?
你可以这样写:
uint32_t endCount = 0; // unsigned int is machine dependent...better use stdint.h...
...
scanf("%u", &endCount);
旨在产生第二个 printf 的语句的输出...
This program will compute 5^N; enter N: 2147483648
The value exceeds the supported numerical range
旨在产生第一个 printf 的语句的输出...
This program will compute 5^N; enter N: -10
The value exceeds the supported numerical range
请查看此程序在您的系统上为此输出的内容...
uint32_t endCount;
/* Read value of N */
printf("This program will compute 5^N; enter N: ");
scanf("%u", &endCount);
printf("entered value = %d (as signed)\n",endCount);
printf("entered value = %u (as unsigned)\n",endCount);
在我的系统上:
This program will compute 5^N; enter N: -10
entered value = -10 (as signed)
entered value = 4294967286 (as unsigned)
我在编写一个要求用户输入值 N 然后输出结果 5^N 的程序时遇到了问题。问题是,如果用户输入的数字大于 (2^31)-1,他们的数字就会溢出,程序会给他们一个错误的答案。
我所做的是将用户给出的整数值赋给一个无符号长整数值。这样如果程序可以检查是否输入了大于 (2^31)-1 的数字,因为 unsigned long 可以容纳比 signed int 多得多的正整数。这样做会使程序正常运行,因为我可以检查是否发生了溢出。
然而我的问题是:当用户输入一个大于 2^31 - 1 的值到原始有符号整数变量(这应该会导致它溢出)时,为什么我可以分配这个溢出的值进入无符号并得到 "correct" 数字是什么?仅在尝试对该数字进行操作时才会发生溢出吗?内存是否存储实际数字(不受位宽限制)?
int endCount;
unsigned long endCountUn; /* power N */
/* Read value of N */
printf("This program will compute 5^N; enter N: ");
scanf("%d", &endCount);
/*
User's value put into unsigned long. Helps with detecting overflow.
*/
endCountUn = endCount;
if ( (endCount < 0) && (endCountUn < 2147483648) )
{
printf("The operation is undefined for negative integers\n");
}
else if ( endCountUn > 2147483647 )
{
printf("The value exceeds the supported numerical range\n");
}
if ( (endCount < 0) && (endCountUn < 2147483648) )
对满足两个条件的数字n执行此if块。
endCount
,是一个(32 位)有符号整数,以 2 的补码表示。
因此,表达式的第一项选择设置了高位的所有 n:
范围 1:[0x80000000...0xFFFFFFFF]
第二项选择范围
内的所有n
范围 2:[0x00000000..0x7FFFFFFF]。
两个范围内的 n 的集合是空集。
因此,您上面的 if 主体将永远不会被执行。
第二个 if(else if 部分)要求范围 1 中的值。
因此,您的测试代码可以简化为:
if( endCount < 0 ) { printf("Value out of range"); }
因为,无论用户输入什么(负数或范围 1 中的值),endCount 始终为负数。
最后,如果您只想允许无符号整数值,为什么首先使用 scanf("%d",endCount)
?
你可以这样写:
uint32_t endCount = 0; // unsigned int is machine dependent...better use stdint.h...
...
scanf("%u", &endCount);
旨在产生第二个 printf 的语句的输出...
This program will compute 5^N; enter N: 2147483648
The value exceeds the supported numerical range
旨在产生第一个 printf 的语句的输出...
This program will compute 5^N; enter N: -10
The value exceeds the supported numerical range
请查看此程序在您的系统上为此输出的内容...
uint32_t endCount;
/* Read value of N */
printf("This program will compute 5^N; enter N: ");
scanf("%u", &endCount);
printf("entered value = %d (as signed)\n",endCount);
printf("entered value = %u (as unsigned)\n",endCount);
在我的系统上:
This program will compute 5^N; enter N: -10
entered value = -10 (as signed)
entered value = 4294967286 (as unsigned)