小明思考

高性能服务器端计算
posts - 70, comments - 428, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

诡异的C

Posted on 2006-01-09 14:04 小明 阅读(1661) 评论(12)  编辑 收藏 引用 所属分类: C/C++

1.无穷loop

int i,a[10];
for(i=0;i<=10;++i)
{
     a[i] 
= 0 ;
}

why?
函数运行时堆栈:
a[0] a[1] ....a[9] i
a[10] = 0;改变i的值为0,造成无穷循环

2.八进制的误用

int i[] = {    012,
                  
024,
                  
125,
           };


为了对齐可能造成的错误,变成了八进制

3.如何调用地址为0的过程?
(*(void(*)())0)();
ps:在大多数现代操作系统,进程引用的地址为虚拟地址,所以这个调用可能合法


4.运算符的优先级

int i = 1;
= i<<4 + 2;

这时i的值是多少?
不是18,是64,因为 i=i<<4+2; <==> i=i<<(4+2);

5.悬挂的if

if(x==0//1
      if(y==0) error(); //2
else//3
       z=x+y;
       f(
&z);
}

C中的else总是和最近的if匹配,所以3和2匹配,而不是和1匹配。等价于

if(x==0//1
{
      
if(y==0) error(); //2
      else//3
           z=x+y;
           f(
&z);
      }
}


解决方法:总是使用{}和if配对

           

Feedback

# re: 诡异的C  回复  更多评论   

2006-01-09 15:11 by vender
原则上i和a[10]的地址没有关联性,一不一样全凭编译器高兴,无论如何越界访问总是个错误

# re: 诡异的C  回复  更多评论   

2006-01-09 16:30 by vender
不试也知道这种布局纯粹是编译器相关的,标准未有规定,编译器完全可以令i和a[10]所在单元不同,当然也可以相同

而且,你没试试吧楼主,例
#include <stdio.h>
int main(int argc, char *argv[])
{
int i, a[10];
printf("%p, %p", &i, a + 10);
for(i = 0; i <= 10; ++i)
a[i] = 0;
return 0;
}
存为任意.c或者.cpp文件,我使用了gcc 3.4.2、vc6、vc7.1分别测试,只有vc6中两者单元同一,其余都是不同,如gcc产出的二进制目标打印出0022FF6C, 0022FF58

正是因为两者没有必要一致,编译器才可以在可能发生越界处(如物理位置a[10]a[11]...处)加入一些额外的验证数据,以便在退出local scope时检验是否有越界发生

# to:vender  回复  更多评论   

2006-01-09 16:51 by 小明
你说的很对,c/c++标准确实没规定
看来这个无穷loop确实是跟编译器有关
谢谢

# re: 诡异的C  回复  更多评论   

2006-01-10 17:41 by 3721
To vender:
照你这么说,是不是可以认为这是VC6比较弱*的地方,好好的大块儿内存不用偏偏要去连续分配,为了减少内存片片?!

# to 3721  回复  更多评论   

2006-01-10 21:12 by vender
这个不是编译器强弱的标准,具体如何使用栈肯定要根据需要

不知道“片片”是否为“碎片”,如果是,那么可能对此你有误解,在栈上分配释放内存不存在碎片的问题,栈的分配和释放总是发生在栈顶,绝对不会发生低地址的空间尚未释放就先释放相对高地址的空间的,由此可见,占用的空间只有一块,哪来碎片呢?

btw:3721这几个字真恶心,呵呵

# re: 诡异的C  回复  更多评论   

2006-01-11 22:01 by 小川
#include <iostream>
using namespace std;
void main(void)
{
int i=0,a[10];
for (i=0;i<=10;i++)
{
a[i]=0;
cout<<"a["<<i<<"]="<<a[i]<<" ";
cout<<"&i="<<&i<<" "<<endl;
cout<<"a="<<a<<" "<<"size="<<sizeof(a)<<endl;
}
}
我也试了一下,用的是VC6.0,嘿嘿
当数组不越界时,是没有问题的。越界时,由于&i(OX0012FF7C)与越界的第一个元素地址相等,即a(数组首地址)+sizeof(a)(数组所占用地址单元)=0X0012FF54+40=OX0012FF7C相当于越界元素是i的引用,从而引起i值变化。但如果赋给a[i]的值不在i的变化范围(0-10)之内的话,是不会产生死循环的。
不知是什么原因,请各位高手不吝赐教!小弟在此谢过!

# re: 诡异的C  回复  更多评论   

2006-01-13 16:02 by Terry
楼上的C++ code也同样可以产生无限循环吗?
再次证明VC 对 stack的使用存在问题

# re: 诡异的C  回复  更多评论   

2006-01-13 20:45 by 小川
是的,嘿嘿
后来想想,如果赋给a[i]的值不在i的变化范围(0-10)之内的话
当i变成了a[i]值,i不满足循环条件,跳出for循环。

# re: 诡异的C  回复  更多评论   

2006-01-19 22:00 by rotcet
看栈是怎么分配的了,这个是编译器相关的,临时变量先分配于寄存器和栈中的,所以如果寄存器够多的话甚至可能i和a[]都直接分配在寄存器中,那样的话这个肯定不会出问题的,如果都刚好分配在栈里的话,那就要看分配策略了吧,,

# re: 诡异的C  回复  更多评论   

2006-02-05 20:00 by 阵雨
无聊,明明是人犯的错误偏要算到编译器头上
还有那个3721傻蛋,VC6能表现出死循环说你还说他弱?难道不表现出来就是好现象〉?

# re: 诡异的C^  回复  更多评论   

2006-03-31 11:13 by 雪代
同意楼上,这明明是人犯的错误和编译器好坏有什么关系?莫名其妙

# re: 诡异的C  回复  更多评论   

2008-05-30 21:41 by zzningxp
你把那个10改成16, g++也会出错~

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理