急求c语言教程整型数据溢出怎么办

c语言 整型数据溢出问题_百度知道
c语言 整型数据溢出问题
请问及孙吉是怎么输出溢出数据的!能详细说下吗,不懂?但是,作为新手,原理是什么?有的说是截取该数16进制后8位进行输出;接着让计算机输出a;然后令a=357我定义 int a
提问者采纳
int类型一般是-,你这数字明显超出范围啊。
我要数据溢出原理
刚才特地跑了一下,原数对应16进制是913017ABDAC5,实际输出是,恰好是16进制后8位,即17ABDAC5。
提问者评价
你真棒,学习了
其他类似问题
整型数据的相关知识
按默认排序
其他3条回答
b);}a=32767
b=-327681111
3276732767加1后变为0000
-32768的补码形式注;;#include &*数据溢出*/n&quot,b,%d\
b=a+1,a.h&%d#include &quot。;main(){
&#47:数据在存储是都是以二进制的补码形式存储的。.h&quot
数据存储到内存是按照2进制存储的int型只能保存32位(二进制),如果超出了就会把前边的溢出了,就是保留后边的,前边的扔掉了 具体的还要涉及到正数和负数的问题,有符号的话,第一位是表示符号的
int 型 占4字节(所占字节和编译器有关的,此处所说的是在VC上,比如在TC或BC上占2字节)有符号 int 范围 -2^31~2^31-1无符号 int 范围 0~2^32-1如果超出这个范围就会溢出
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁502 Bad Gateway
502 Bad Gateway
nginx/1.2.71966人阅读
栽到一个简单的坑里了,怪自己基础不牢,网上查了下,中文的结果貌似没有写这个的,所以发出来。
下面的代码,变量 i 的值是多少呢:
#define P (64*1024)
long long i = P * P;
答案是 i 溢出了,暂时我看到结果 i = 0(当然这很有可能结果属于未定义)。
解决的关键是,对于运算可能出现超出int范围的常数,一律声明为long,比如
#define P (64*1024l)
其中的关键是常数在C语言的运算中是什么类型的,长度多少。
首先一个前提,常数本身可以存储为int不溢出,否则声明常数的时候就必须带&l&或者&ll&后缀,也就不存在上面的乘法溢出的错误;
然后如果跟常数运算的是变量,那么运算结果的类型与该变量相同。一般对于变量的长度,声明时候会加以注意,不至于栽到溢出的坑里;
最后就是上面这种情况了,常数与常数运算,结果的类型与接收结果的变量无关,只与声明常数时的后缀有关。因此在做常数的宏声明时,务必考虑可能出现的溢出情况,保险的话,尽量声明为long,因为真正使用宏的时候,是很难注意常数运算会不会溢出的!
最后的最后,编译器的警告需要认真对待!!
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:88499次
积分:1394
积分:1394
排名:第14393名
原创:50篇
转载:26篇
评论:10条
(1)(1)(3)(1)(2)(1)(3)(1)(3)(1)(1)(1)(1)(2)(7)(4)(5)(1)(3)(6)(9)(4)(4)(3)(2)(3)(3)你的位置: > C语言的整型溢出问题
整型有点老生常谈了,bla, bla, bla… 但似乎没有引起多少人的重视。整型会有可能导致溢出,溢出会导致各种攻击,比如最近OpenSSL的heartbleed事件,就是一个buffer overread的事件。在这里写下这篇文章,希望大家都了解一下整型溢出,编译器的行为,以及如何防范,以写出更的代码。
什么是整型溢出
C语言的整型问题相信大家并不陌生了。对于整型溢出,分为无符号整型溢出和有符号整型溢出。
对于unsigned整型溢出,C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”,也就是说,如果一个unsigned char(1字符,8bits)溢出了,会把溢出的值与256求模。例如:
unsigned char x = 0
printf(&%d/n&, ++x);
上面的代码会输出:0 (因为0xff + 1是256,与2^8求模后就是0)
对于signed整型的溢出,C的规范定义是“undefined behavior”,也就是说,编译器爱怎么实现就怎么实现。对于大多数编译器来说,算得啥就是啥。比如:
signed char x =0x7f; //注:0xff就是-1了,因为最高位是1也就是负数了
printf(&%d/n&, ++x);
上面的代码会输出:-128,因为0x7f + 0×01得到0×80,也就是二进制的,符号位为1,负数,后面为全0,就是负的最小数,即-128。
另外,千万别以为signed整型溢出就是负数,这个是不定的。比如:
signed char x = 0x7f;
signed char y = 0x05;
signed char r = x *
printf(&%d/n&, r);
上面的代码会输出:123
相信对于这些大家不会陌生了。
整型溢出的危害
下面说一下,整型溢出的危害。
示例一:整形溢出导致死循环
short len = 0;
while(len& MAX_LEN) {
len += readFromInput(fd, buf);
上面这代码可能是很多都喜欢写的代码(我在很多代码里看到过多次),其中的MAX_LEN 可能会是个比较大的整型,比如32767,我们知道short是16bits,取值范围是-32768 到 32767 之间。但是,上面的while循环代码有可能会造成整型溢出,而len又是个有符号的整型,所以可能会成负数,导致不断地死循环。
示例二:整形型时的溢出
int copy_something(char *buf, int len)
#define MAX_LEN 256
char mybuf[MAX_LEN];
if(len & MAX_LEN){ // &---- [1]
return -1;
return memcpy(mybuf, buf, len);
上面这个例子中,还是[1]处的if语句,看上去没有会问题,但是len是个signed int,而memcpy则需一个size_t的len,也就是一个unsigned 类型。于是,len会被提升为unsigned,此时,如果我们给len传一个负数,会通过了if的检查,但在memcpy里会被提升为一个正数,于是我们的mybuf就是overflow了。这个会导致mybuf缓冲区后面的被重写。
示例三:分配
关于整数溢出导致堆溢出的很典型的例子是,OpenSSH Challenge-Response SKEY/BSD_AUTH 远程缓冲区溢出。下面这有问题的代码摘自OpenSSH的代码中的auth2-chall.c中的input_userauth_info_response() 函数:
nresp = packet__int();
if (nresp & 0) {
response = xmalloc(nresp*sizeof(char*));
for (i = 0; i & i++)
response[i] = packet__string(NULL);
上面这个代码中,nresp是size_t类型(size_t一般就是unsigned int/long int),这个示例是一个解的示例,一般来说,数据中都会有一个len,然后后面是data。如果我们精心准备一个len,比如:(在32位系统上,指针占4个字节,unsigned int的最大值是0xffffffff,我们只要提供0xffffffff/4 的值——0×,这里我们设置了0×4000000 + 1), nresp就会读到这个值,然后nresp*sizeof(char*)就成了
* 4,于是溢出,结果成为了 0×,然后求模,得到4。于是,malloc(4),于是后面的for循环 次,就可以干环事了(经过0×的循环,用户的数据早已覆盖了xmalloc原先分配的4字节的空间以及后面的数据,包括程序代码,函数指针,于是就可以改写程序逻辑。关于更多的东西,你可以看一下这篇文章《》)。
示例四:缓冲区溢出导致问题
int func(char *buf1, unsigned int len1,
char *buf2, unsigned int len2 )
char mybuf[256];
if((len1 + len2) & 256){
//&--- [1]
return -1;
memcpy(mybuf, buf1, len1);
memcpy(mybuf + len1, buf2, len2);
do_some_stuff(mybuf);
上面这个例子本来是想把buf1和buf2的内容copy到mybuf里,其中怕len1 + len2超过256 还做了判断,但是,如果len1+len2溢出了,根据unsigned的特性,其会与2^32求模,所以,基本上来说,上面代码中的[1]处有可能为假的。(注:通常来说,在这种情况下,如果你开启-O代码选项,那个if语句块就全部被和谐掉了——被编译器给删除了)比如,你可以测试一下 len1=0×104, len2 = 0xfffffffc 的情况。
这样的例子有很多很多,这些整型溢出的问题如果在的地方,尤其是在搭配有用户输入的地方,如果被利用了,就会导致很严重的安全问题。
关于编译器的行为
在谈一下如何正确的检查整型溢出之前,我们还要来学习一下编译器的一些东西。请别怪我罗嗦。
如何检查整型溢出或是整型变量是否合法有时候是一件很麻烦的事情,就像上面的第四个例子一样,编译的优化参数-O/-O2/-O3基本上会假设你的程序不会有整形溢出。会把你的代码中检查溢出的代码给优化掉。
关于编译器的优化,在这里再举个例子,假设我们有下面的代码(又是一个相当相当常见的代码):
if (data + len & data){
printf(&invalid len/n&);
上面这段代码中,len 和 data 配套使用,我们害怕len的值是非法的,或是len溢出了,于是我们写下了if语句来检查。这段代码在-O的参数下正常。但是在-O2的编译选项下,整个if语句块被优化掉了。
你可以写个小程序,在gcc下编译(我的是4.4.7,记得加上-O2和-g参数),然后用g调试时,用disass /m命信输出汇编,你会看到下面的结果(你可以看到整个if语句块没有任何的汇编代码——直接被编译器和谐掉了):
int len = 10;
char* data = (char *)malloc(len);
0x04d4 &+4&:
0x04d9 &+9&:
0x4003b8 &malloc@plt&
if (data + len & data){
printf(&invalid len/n&);
0x04de &+14&:
0x04e2 &+18&:
对此,你需要把上面 char* 型成 uintptr_t 或是 size_t,说白了也就是把char*成unsigned的数据结构,if语句块就无法被优化了。如下所示:
if ((uintptr_t)data + len & (uintptr_t)data){
关于这个事,你可以看一下C99的规范说明《
》第 §6.5.6 页,第8点,我截个图如下:(这段话的意思是定义了指针+/-一个整型的行为,如果越界了,则行为是undefined)
注意上面标红线的地方,说如果指针指在数组范围内没事,如果越界了就是undefined,也就是说这事交给编译器实现了,编译器想咋干咋干,那怕你想把其优化掉也可以。在这里要重点说一下,C语言中的一个大恶魔—— Undefined! 这里都是“野兽出没”的地方,你一定要小心小心再小心。
花絮:编译器的彩蛋
上面说了所谓的undefined行为就全权交给编译器实现,gcc在1.17下对于undefined的行为还玩了个彩蛋()。
下面gcc 1.17版本下的遭遇undefined行为时,gcc在unix发行版下玩的彩蛋的源代码。我们可以看到,它会去尝试去执行一些,
或是Emacs的 ,如果找不到,就输出一条NB的报错。
execl(&/usr/games/hack&, &#pragma&, 0); // try to run the game NetHack
execl(&/usr/games/rogue&, &#pragma&, 0); // try to run the game Rogue
// try to run the Tower's of Hanoi simulation in Emacs.
execl(&/usr/new/emacs&, &-f&,&hanoi&,&9&,&-kill&,0);
execl(&/usr/local/emacs&,&-f&,&hanoi&,&9&,&-kill&,0); // same as above
fatal(&You are in a maze of twisty compiler features, all different&);
正确检测整型溢出
在看过编译器的这些行为后,你应该会明白——“在整型溢出之前,一定要做检查,不然,就太晚了”。
我们来看一段代码:
void foo(int m, int n)
size_t s = m +
上面这段代码有两个风险:1)有符号转无符号,2)整型溢出。这两个情况在前面的那些示例中你都应该看到了。所以,你千万不要把任何检查的代码写在 s = m + n 这条语名后面,不然就太晚了。undefined行为就会出现了——用句纯正的英文表达就是——“Dragon is here”——你什么也控制不住了。(注意:有些初学者也许会以为size_t是无符号的,而根据优先级 m 和 n 会被提升到unsigned int。其实不是这样的,m 和 n 还是signed int,m + n 的结果也是signed int,然后再把这个结果转成unsigned int 赋值给s)
比如,下面的代码是错的:
void foo(int m, int n)
size_t s = m +
if ( m&0 && n&0 && (SIZE_MAX - m & n) ){
//error handling...
上面的代码中,大家要注意 (SIZE_MAX – m & n) 这个判断,为什么不用m + n & SIZE_MAX呢?因为,如果 m + n 溢出后,就被截断了,所以表达式恒真,也就检测不出来了。另外,这个表达式中,m和n分别会被提升为unsigned。
但是上面的代码是错的,因为:
1)检查的太晚了,if之前编译器的undefined行为就已经出来了(你不知道什么会发生)。
2)就像前面说的一样,(SIZE_MAX – m & n) 可能会被编译器优化掉。
3)另外,SIZE_MAX是size_t的最大值,size_t在64位系统下是64位的,严谨点应该用INT_MAX或是UINT_MAX
所以,正确的代码应该是下面这样:
void foo(int m, int n)
size_t s = 0;
if ( m&0 && n&0 && ( UINT_MAX - m & n ) ){
//error handling...
s = (size_t)m + (size_t)n;
在《》(PDF)中,第28页的代码中:
如果n和m都是signed int,那么这段代码是错的。正确的应该像上面的那个例子一样,至少要在n*m时要把 n 和 m 给 cast 成 size_t。因为,n*m可能已经溢出了,已经undefined了,undefined的代码转成size_t已经没什么意义了。(如果m和n是unsigned int,也会溢出),上面的代码仅在m和n是size_t的时候才有效。
不管怎么说,《》绝对值得你去读一读。
上溢出和下溢出的检查
前面的代码只判断了正数的上溢出overflow,没有判断负数的下溢出underflow。让们来看看怎么判断:
对于加法,还好。
#include &limits.h&
void f(signed int si_a, signed int si_b) {
if (((si_b & 0) && (si_a & (INT_MAX - si_b))) ||
((si_b & 0) && (si_a & (INT_MIN - si_b)))) {
/* Handle error */
sum = si_a + si_b;
对于乘法,就会很复杂(下面的代码太夸张了):
void func(signed int si_a, signed int si_b)
if (si_a & 0) {
/* si_a is positive */
if (si_b & 0) {
/* si_a and si_b are positive */
if (si_a & (INT_MAX / si_b)) {
/* Handle error */
} else { /* si_a positive, si_b nonpositive */
if (si_b & (INT_MIN / si_a)) {
/* Handle error */
} /* si_a positive, si_b nonpositive */
} else { /* si_a is nonpositive */
if (si_b & 0) { /* si_a is nonpositive, si_b is positive */
if (si_a & (INT_MIN / si_b)) {
/* Handle error */
} else { /* si_a and si_b are nonpositive */
if ( (si_a != 0) && (si_b & (INT_MAX / si_a))) {
/* Handle error */
} /* End if si_a and si_b are nonpositive */
} /* End if si_a is nonpositive */
result = si_a * si_b;
更多的防止在操作中整型溢出的安全代码可以参看《》
对于C++来说,你应该使用STL中的numeric_limits::max() 来检查溢出。
另外,微软的SafeInt类是一个可以帮你远理上面这些很tricky的类,下载地址:
对于Java 来说,一种是用JDK 1.7中Math库下的safe打头的函数,如safeAdd()和safeMultiply(),另一种用更大尺寸的数据类型,最大可以到BigInteger。
可见,写一个安全的代码并不容易,尤其对于C/C++来说。对于来说,他们只需要搜一下开源中代码有memcpy/strcpy之类的地方,然后看一看其周边的代码,是否可以通过用户的输入来影响,如果有的话,你就惨了。
最后, 不好意思,这篇文章可能罗嗦了一些,大家见谅。
(全文完)
(转载本站文章请注明作者和出处
,请勿用于任何商业用途)
——=== 访问
寻找遗失儿童。 ===——
Heartbleed说成buffer overread更准确。Buffer overflow一般是指overwrite。
嗯,你的说法更严谨一些。我在文中修改一下。
示例二中,len能通过if检查,说明它转换成unsigned不大于sizeof(mybuf),所以memcpy调用还是安全的。
示例二的确如你所说,不过在以前的有些c89的编译器并不是这样的行为(应该是编译器的bug)。为了更为严谨一些,我修改了一下,检查条件不再用sizeof了,而是用一个宏。
溢出后的数会以2*sizeof(type)作模运算 应该是2^sizeof(type)
sizeof(type) 得出的值应该是type所占的字节数,要得到type所占的位(bits)还要再乘8
对于unsigned整型溢出,C的规范是有定义的——“溢出后的数会以2*sizeof(type)作模运算”, 这里溢出后数应该以 2的sizeof(type)次方作模运算吧?
谢谢楼上三位,已更正。
第二例: “此时,如果我们给len传一个负数,被提升为一个正数,通过了if的检查” 如果负数被自动提升为整数,那么是一个大于INT_MAX的值,通不过if检查的
每次看到陈老师发文章,总是想着先搁着以后看,结果因为太忙,搁着好多文章木看,= =
陈老师:在gcc (GCC) 4.4.6
(Red Hat 4.4.6-3)下 signed char x =0x7f; printf(“%d/n”, x+1); 打印出128啊
不过手算也不应该是128
对不起,应该被提升成int了。应该是 ++x
示例四:缓冲区溢出导致安全问题, 这个我在VS2010中测试了一下,len1和len2均为10时和设置为250时,没有溢出现象,没有你所说的问题而全部按”预期”执行.if((len1 + len2) & 256) 这里,虽然len1和len2都是unsigned char类型,我猜在编译器看来常数256可能是整形,于是在做计算和判断时自动转成了整型了.没有时间做更深入的研究,大家有兴趣或许可以继续
不用猜,你是对的。被提升成int了。我修改了一下源文。不用unsigned char,改成unsigned int,这样就更清楚了。
: 陈老师:在gcc (GCC) 4.4.6
(Red Hat 4.4.6-3)下 signed char x =0x7f; printf(“%d/n”, x+1); 打印出128啊
(x+1)时x被提升成int了。试试:
signed char x =0x7f; printf(“%d/n”, ++x);
您在文中提到“注意:有些初学者也许会以为size_t是无符号的,而根据优先级 m 和 n 会被提升到unsigned int。其实不是这样的,m 和 n 还是signed int,m + n 的结果也是signed int,然后再把这个结果转成unsigned int 赋值给s”,好吧,我就是初学者,我还真的是这么认为的。经过我在VS2010中的测试,好象还真的是这样的。而在前些年我写的C语言解释器中针对变量类型不一致的情况,我的处理方案就是先转成最大最精确的类型再计算(其实就是在计算的过程中按最大最精确的类型来解读)。我想不出先按原类型计算出结果后再转成新类型的理由,谁能帮我解释一下这么做的理由呢?
第一个和第二个例子 我在Mac 下得出结果是 256 和128 。
: 您在文中提到“注意:有些初学者也许会以为size_t是无符号的,而根据优先级 m 和 n 会被提升到unsigned int。其实不是这样的,m 和 n 还是signed int,m + n 的结果也是signed int,然后再把这个结果转成unsigned int 赋值给s”,好吧,我就是初学者,我还真的是这么认为的。经过我在VS2010中的测试,好象还真的是这样的。而在前些年我写的C语言解释器中针对变量类型不一致的情况,我的处理方案就是先转成最大最精确的类型再计算(其实就是在计算的过程中按最大最精确的类型来解读)。我想不出先按原类型计算出结果后再转成新类型的理由,谁能帮我解释一下这么做的理由呢?
“m + n”是个表达式,而”s = xxx”是另一个表达式;隐式类型转换肯定是先发生在优先级更高的表达式内,赋值表达式优先级最低,因此先进行”m + n”的类型推导,结论是,双方都是int无需转换,然后再处理表达式”size_t = int”将右边类型提升
而你的设想则是反过来,根据优先级最低的表达式得到最大类型,再由外向内将各个更高优先级进行类型扩展后才开始算数运算…这才是奇怪哦 “sqrt(i1 / i2)”,结果可能对一个小数开方哦…
《安全编码规范》那段有点没看明白 连续判断了n&0 m&0 而且 SIZE_MAX/n &m, n是整数则除法不应该溢出… 能不能举个简单的反例? 多谢
SafeInt类是一个可以帮你远(理)上面
void foo(int m, int n) {
size_t s = 0;
if ( m&0 && n&0 && ( UINT_MAX - m & n ) ){
//error handling...
s = (size_t)m + (size_t)n; }
里面,UINT_MAX 换成 SIZE_MAX 也是可以的,因为后面已经把两个数转换成 size_t 了,所以即使 m + n 会溢出,(size_t)m + (size_t)n 也不会溢出。
不一样,SIZE_MAX在64位系统下是64位的最大数。而UINT_MAX还是32位的
: 不用猜,你是对的。被提升成int了。我修改了一下源文。不用unsigned char,改成unsigned int,这样就更清楚了。
印象中char/unsigned char溢出会涉及到C99中整形提升的概念,保证中间变量不会溢出.所以此处char不会有问题. 但是int/unsigned int溢出会出现问题.
: 您在文中提到“注意:有些初学者也许会以为size_t是无符号的,而根据优先级 m 和 n 会被提升到unsigned int。其实不是这样的,m 和 n 还是signed int,m + n 的结果也是signed int,然后再把这个结果转成unsigned int 赋值给s”,好吧,我就是初学者,我还真的是这么认为的。经过我在VS2010中的测试,好象还真的是这样的。而在前些年我写的C语言解释器中针对变量类型不一致的情况,我的处理方案就是先转成最大最精确的类型再计算(其实就是在计算的过程中按最大最精确的类型来解读)。我想不出先按原类型计算出结果后再转成新类型的理由,谁能帮我解释一下这么做的理由呢?
“m + n”是个表达式,而”s = xxx”是另一个表达式;隐式类型转换肯定是先发生在优先级更高的表达式内,赋值表达式优先级最低,因此先进行”m + n”的类型推导,结论是,双方都是int无需转换,然后再处理表达式”size_t = int”将右边类型提升 而你的设想则是反过来,根据优先级最低的表达式得到最大类型,再由外向内将各个更高优先级进行类型扩展后才开始算数运算…这才是奇怪哦 “sqrt(i1 / i2)”,结果可能对一个小数开方哦…
参考 整型提升
size_t 是由编译器参数决定sign还是unsign的. 所以具体还是要看编译选项.尤其是嵌入式编译器. 曾经碰到不同的编译器,同样的char型,默认一个(TI IAR)解释为unsigned,一个(日本瑞萨)解释为signed,需要勾选相关选项才行.
这几天在看《深入理解计算机系统》,里面就提到了四则运算的溢出问题
: 您在文中提到“注意:有些初学者也许会以为size_t是无符号的,而根据优先级 m 和 n 会被提升到unsigned int。其实不是这样的,m 和 n 还是signed int,m + n 的结果也是signed int,然后再把这个结果转成unsigned int 赋值给s”,好吧,我就是初学者,我还真的是这么认为的。经过我在VS2010中的测试,好象还真的是这样的。而在前些年我写的C语言解释器中针对变量类型不一致的情况,我的处理方案就是先转成最大最精确的类型再计算(其实就是在计算的过程中按最大最精确的类型来解读)。我想不出先按原类型计算出结果后再转成新类型的理由,谁能帮我解释一下这么做的理由呢?
“m + n”是个表达式,而”s = xxx”是另一个表达式;隐式类型转换肯定是先发生在优先级更高的表达式内,赋值表达式优先级最低,因此先进行”m + n”的类型推导,结论是,双方都是int无需转换,然后再处理表达式”size_t = int”将右边类型提升 而你的设想则是反过来,根据优先级最低的表达式得到最大类型,再由外向内将各个更高优先级进行类型扩展后才开始算数运算…这才是奇怪哦 “sqrt(i1 / i2)”,结果可能对一个小数开方哦…
我错了,受前面的影响把“signed int”看成了“signed char”,面壁去。
耗哥, 我觉得读完之后再也写不出安全代码了啊
char 是否有符号是编译器决定。size_t 对应的有符号类型是 ssize_t。
看了博客,第一反应是整形提升的问题。对于代码中的数字常量,一般会用int来表示。当表示范围低于int类型的变量参加运算或者传递参数时会进行整形提升。当然已经有人指出了,这里我补充一个小点,并且有一个牛的测试网址,希望对大家有帮助。
unsigned char x = 0xff 这就是为什么:x++,x+1等的值是一个正确的值。但是++x却符合作者的意图,这应该是后置和前置的区别把。
short y = 1; y = y + 1; // 会有警告,精度丢失的可能 y += 1; // 没有警告
在《鸟哥Linux私房菜》中有一篇就是讲解整型提升的问题。整型提升的问题。当有符号数和无符号数进行大小比较时,这里会存在一个大坑:
1. 有符号数的范围比无符号数表示范围大(有符号数可以表示无符号数),Ok,这个没事。 2. 有符号数表示的范围范围没有无符号数大(有符号数的精度无法表示无符号数),那么此时有符号数会用无符号数的精度来表示,即通过+/- 2^n来快速进入无符号数的范围(都是整数就无所谓了)。这样你会看见负数会大于整数的结果。
#include &iostream& #include &climits&
int main() {
int x = -1;
int z = 1;
unsigned long y = INT_MAX + 1;
if (x & y)
cout && &BINGO& &&
if (z & y)
cout && &BINGO& &&
return EXIT_SUCCESS; }
你懂整数么?那么来测试一下。这个国外人整理的测试。
两个头没了
示例4不太懂,len1+len2的时候不会提升到int型吗,那个if怎么会被优化呢
: 示例4不太懂,len1+len2的时候不会提升到int型吗,那个if怎么会被优化呢
没事了,网页放了半天没刷新
我试了一下编译器优化的那个示例。的确,gcc 会把 if (data + len
puts(“overflow!”);
printf(“%hd + %hd = %d/n”, a, b, a + b);
return 0; }
我用的是 gcc 4.8.2。
永远都不要用unsigned,对待项目代码已有的unsigned要小心,不要贪恋正整形两倍的表示空间,也不要代码文档化地告诉其他人这个是正整型。
请问下,JAVA1.7 中Math的safe打头的函数,指的是什么?
编译的时候做一下静态检查,这样类型不匹配的问题都能发现。
陈兄对各种语言都很精通啊。。。
Java 1.7中,Math里有safe打头的函数吗?我在java API中没有找到
示例四中说“被编译器给删除了”,我觉得容易让人误解——好像是在说编译器会在编译的时候就把它优化去掉
不太明白,转成宏之后有什么问题,len是负数还能过if那条语句么?
耗子叔,写的很棒
如果给len传一个负数,怎么过了if的检查?难道不是两个int比较?
看完,没法写代码了~~~
我记得以前Google的C++代码规范里说过用整数的原则:一是除非表示位组,否则不要用无符号数。需要进行算术计算的数字一概用有符号,就是为了一定程度上避免整数转型出乎意料。然后如果有32位溢出的可能,就上64位。就现在来说除非科学计算,一般不至于连64位的int64_t都会溢出。
另外,微软的SafeInt类是一个可以帮你远理上面这些很tricky的类,下载地址:/
「远理」-&「远离」?
示例一的算法对么,len代表读的总长度,buf每次都累加上,好像不对吧,是不是应该改成
len += readFromInput(fd, buf+len);
在《安全编码规范》(PDF)中,第28页的代码中: if (n & 0 && m & 0 && SIZE_MAX/n &= m) {
size_t bytes = n * }
没发现什么问题, /unix系统 SIZE_MAX定为机器字长所表示的最大值与size_t的最大值相同,请问耗哥我的解释有不妥之处没?
不好意思,给你挑个问题。编译器优化一节下的例子我认为是错误的。我尝试了一下,按你的写法,-O2确实会把if优化掉,但是len都没有初始化!如果data和len是函数的参数的话,if块完全没有问题。如果len是一个可能为负的算式的话,if块也没有问题。
我一开始也觉得没问题,仔细看了之后,发现如果n和m是32位整数而系统是64位的话,还是会出问题。比如,n=0×10000,m=0×10001,在64位系统上会得到bytes=65536而不是出错。用UINT_MAX替换SIZE_MAX可以解决这个问题。
估计是输入法作祟,上条居然0x变成0×了。抱歉。
老师辛苦了。学习了 谢谢分享。 也希望楼主有空去我玩玩。
JAVA7中Math库没有safe*函数,望修正。
写代码不易,写安全的代码更不易,且行且珍惜~~~
for(unsigned char i = 0; i
printf(“overflow/n”);
} 可以运行,请问浩歌,是为什么呢?C语言在什么情况下进行类型提升?
寻找遗失儿童!
酷壳建议大家多使用RSS访问阅读(本站已经是全文输出,推荐使用 或 )。有相关事宜欢迎电邮:haoel(。最后,感谢大家对酷壳的和体谅!
为本站提供
转载请注明: &
与本文相关的文章

我要回帖

更多关于 c语言教程 的文章

 

随机推荐