C/C++编程新手错误语录(续二)

2016-02-19 20:21 3 1 收藏

有一种朋友不在生活里,却在生命力;有一种陪伴不在身边,却在心间。图老师即在大家的生活中又在身边。这么贴心的服务你感受到了吗?话不多说下面就和大家分享C/C++编程新手错误语录(续二)吧。

【 tulaoshi.com - 编程语言 】

前文回顾:C/C++编程新手错误语录  错误语录(续一)(13)“整型变量仅仅意味着一个整数” !-- frame contents -- !-- /frame contents --   当我们还是一个新手,看整型就是整数;
  
  当我们成为高手,看什么都是整型。
  
  整型,在所有C/C++基本数据类型中最富有艺术魅力和奇幻色彩。
  
  我们从某闻名论坛的一篇帖子开始一窥整型的奥妙。
  
  问:Vxworks操作系统启动一个任务的函数是taskSpawn(char* name, int priority, int options, int stacksize, FUNCPTR function, int arg1,.. , int arg10),它只接受整型参数,我该怎么办才能给它传一个结构体(在32位PowerPC平台下)?
  
  答:可以传入结构体的指针,在32位PowerPC平台下,指针本质上就是一个32位整数,在函数体内将整型强制转化为结构体指针就可访问结构体的每一个元素。
  
  如:
  //启动任务1
  taskSpawn(“task1”, 180, NULL, 10000, Task1Fun, &pStrUCtAr,0,0,0,0,0,0,0,0,0);
  //task1函数
  Task1Fun ( int arg1 )
  {
  struct_x * pStructx = (struct_x *) arg1; //将整型强制转化为结构体指针
  …
  }
  在此提出“泛整型”的概念,(unsigned)char、(unsigned)short int、(unsigned)int、(unsigned)long int等都属于这个范畴,指针必然属于“泛整型”的范围。用指针的高超境界,也为将其看做一个“泛整型”。
  
  看看软件的具体设计文档,其数据结构定义部分经常看到“INT8、UINT8、INT16、UINT16、INT32、UINT32、INT64、UINT64”或“BYTE、Word、DWORD”等数据类型,它们在本质上都是(unsigned)char、(unsigned)short int、(unsigned)int、(unsigned)long int宏定义的结果,都属于“泛整型”。所以,“泛整型”的概念真实地体现在日常的软件设计当中。
  
更多内容请看C/C++技术专题  Java编程开发手册专题,或
  正因为各种指针类型在本质上都是“泛整型”,因此它们可以互相转化:
  int a, b;
  memset( (char*) &a, (char*) &b, sizeof(int) );
  等价于:
  int a, b;
  a = b; !-- frame contents -- !-- /frame contents --
  从来没有人会用memset( (char*) &a, (char*) &b, sizeof(int) )来代替a = b,这里只是为了说明问题。下面的代码则经常用到:
  int *p = (int *) malloc(100*sizeof(int));
  
   memset ( p, 0, 100*sizeof(int) ); //将申请的内存空间清0
  我们看memset的函数原型为:
  void * memset ( void * buffer, int c, size_t num );
  实际上它接受的第一个参数是无类型指针,在memset函数体内,其它任意类型的指针都向void *转化了。类似的内存操作函数memcpy所接受的源和目的内存地址也是无类型指针。
  
  char *转化为int *后的值虽然不变(还是那个地址),但是其++、--等操作的含义却发生了变化,这也是要注重的。
  char *p;
  ++p;
  与
  char *p;
  ++(int *)p;
  的结果是不一样的,前者的p值加了1,而后者的则增加了sizeof(int)。
  
  下面来剥Windows程序设计中消息传递函数两个参数的皮,看看它们究竟是什么:
  typedef UINT WPARAM;
  typedef LONG LPARAM;
  原来,WPARAM和LPARAM其实都属于“泛整型”,所以不要报怨消息处理函数只能接受“泛整型”。实际上,从指针的角度上来讲,在C/C++中,可以获得任何类型实例(变量、结构、类)的指针,所以Windows的消息处理函数实际上可以接受一切类型的参数。
  
  惊天动地一句话:“泛整型”可表征一切。
  
更多内容请看C/C++技术专题  Java编程开发手册专题,或
  (14)“值传递一定不会改变参数”
  

  理论而言,值传递的确不会改变参数的内容。但是,某年某月的某一天,隔壁Office的硕士mm写了这么一段程序,参数的值却被改变了:
  int n = 9;
  char a[10];
   !-- frame contents -- !-- /frame contents -- example ( n, a ); //调用函数example(int n,char *pStr)
  printf (“%d”, n );  //输出结果不是9
  大概整个office的人都被搞懵了,都说编译器瞎搞,有问题。找到笔者,笔者凭借以往的经常,一眼就看出来不是什么编译器出错,而是在函数example内对字符串a的访问越界!
  
  当在函数example内对a的访问越界后,再进行写操作时,就有可能操作到了n所在的内存空间,于是改变了n的值。
  
  给出这个语录,并非为了推翻“值传递不会改变参数”的结论,而是为了从侧面证实在C/C++语言中,数组越界是多么危险的错误!
  
  下面的两个函数有明显的数组越界:
  void example1()
  {
  char string[10];
  char* str1 = "0123456789";
  strcpy( string, str1 );
  }
  void example 2(char* str1)
  {
  char string[10];
  if( strlen( str1 ) = 10 )
  {
  strcpy( string, str1 );
  }
  }
  而这个函数的越界就不这么明显:
  void example3()
  {
  char string[10], str1[10];
  int i;
  for(i=0; i10; i++)
  {
  str1[i] = 'a';
  }
  strcpy( string, str1 );
  }
  其实,这个函数危险到了极点。因为对于strcpy函数而言,拷贝的时候要碰到’

来源:http://www.tulaoshi.com/n/20160219/1623427.html

延伸阅读
常量是一种标识符,它的值在运行期间恒定不变。C语言用 #define来定义常量(称为宏常量)。C++ 语言除了 #define外还可以用const来定义常量(称为const常量)。 5.1 为什么需要常量 如果不使用常量,直接在程序中填写数字或字符串,将会有什么麻烦? (1) 程序的可读性(可理解性)变差。程序员自己会忘记那些数字或...
第7章 内存治理 欢迎进入内存这片雷区。伟大的Bill Gates 曾经失言: 640K ought to be enough for everybody — Bill Gates 1981 程序员们经常编写内存治理程序,往往提心吊胆。假如不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本章的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地...
作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的。STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现。本教程旨在传播和普及STL的基础知识,若能借此机会为STL的推广做些力所能及的事情,到也是件让人愉快的事情。 1 初识STL:解答一些疑问 1.1 一个最关心的问题:什么是STL "什...
1. 如何获取应用程序的实例句柄? 应用程序的 实例句柄保存在CWinAppIm_hInstance 中,可以这么调用AfxGetInstancdHandle获得句柄. Example: HANDLE hInstance=AfxGetInstanceHandle();  2. 如何通过代码获得应用程序主窗口的指针? 主窗口的 指针保存在CWinThread::m_pMainWnd中,调用 AfxGetMainWnd实现。 AfxG...
以下是侯捷个人收集到的 C/C++ 编程方面的术语对照。请大陆朋友给我一些意见,尤其是标示 '?' 之栏位。谢谢。 两岸朋友,假如您想到哪些术语尚未列入本表,请提示我,谢谢。 新书写作时,我会以此表为叁考。 ●英中繁简编程术语对照 英文          ...

经验教程

882

收藏

46
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部