紫罗兰茶馆

lishengg的紫罗兰茶馆

导航

<2004年10月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

留言簿(4)

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜

2004年10月27日 #

挺好玩的C语句

我在学习VC,或者在阅读别人写的文章的时候,偶尔碰到下面很多有趣的,并且很奇怪的语句,整理起来,以备后忘. 其实有些是不大容易想到的技巧,贴出来权当大伙饭后没事的小品文,当然不要过多的看重类似的语句学习,而忽略了基础知识。
  

一. 奇怪的宏定义
  (1)  #define for if(0); else for 
按照c++标准,for中定义的变量的作用域应该只在for循环中有效,而VC却不行,比如这样定义是不对的
for(int i=0;i<90;i++)
{
...;
}

for(int i=0;i<90;i++)  //重复定义i变量
{
...;
}

如果加上标题的那句,那么就可以了,就是让i作用域局限在else中.  这个问题在net中已经得到解决。


二、宏定义怪圈
#define  wait_event(wq,condition)  \ 
do{  \ 
if(condition)  \ 
                           break;  \ 
             __wait_event(wq,condition);  \ 
}while(0) 


明明这句话只执行一次,为什么还还用do-while语句呢?

假设有这样一个宏定义 
#define  macro(condition)  \ 
if(condition)  dosomething(); 
现在在程序中这样使用这个宏: 
if(temp) 
             macro(i); 
else 
             doanotherthing(); 
一切看起来很正常,但是仔细想想。这个宏会展开成: 
if(temp) 
             if(condition)  dosomething(); 
else   
             doanotherthing(); 
这时的else不是与第一个if语句匹配,而是错误的与第二个if语句进行了匹配,编译通过了,但是运行的结果一定是错误的。为了避免这个错误,我们使用do{….}while(0)  把它包裹起来,成为一个独立的语法单元,从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化,所以使用这种方法也不会导致程序的性能降低。
这个用法在linux源码中很常见。

三、功能强大的解释
除了/* */和 //解释以外,你见过这样的解释方法了吗?
 #if(0)
........
#endif

这样是为了解释掉某段程序,而不影响其中的/*...*/的作用,便于调试,而/*.....*/是不能嵌套的,编译会出错.

四、数组变脸 a[i]和i[a]
   在程序里本应该用a[i],但i[a]竟然和a[i]输出的结果一样。为什么。今天把问题整理如下:
i[a]是标准语法。“[]”称为下标运算符,其语法为:
postfix_expression [ expression ]
其中“postfix_expression”和“expression”之中必须有一个是指针类型(或数组),而另一个是整型。
例如下面的程序是完全合法的:
int a[]={0,1,2,3,4};
printf("%d\n",3[a]);
下标运算符参与的表达式在求解时仅仅是做一个变换而已,将“postfix_expression [ expression ]”
改写为“ * ( postfix_expression + expression ) ”,因此a[3]和3[a]分别改写为*(a+3)和*(3+a),
可见二者是完全等价的。但注意不要用i[a]这种形式,因为它不符合日常习惯。
实验代码:
#include "stdafx.h"
#include "iostream.h"
int f();
int main(int argc, char* argv[])
{

       int a[20]={1,2,3,4,5,6,7,8,9};
       cout<<a[f()]<<endl;
       cout<<f()[a]<<endl;
       return 0;
}

int f()
{
 return 4;
}

实验结果:
4
4
Press any key to continue

五、双胞胎定义和声明:int x;x;

这儿是个关于宏的问题,我曾用过ATL的串转换宏,包括W2A,开始有些东西我还不太明白。为了使用这些宏,必须在函数的开始处用USES_CONVERSION来初始化某些局部变量。用就用吧,但是看看这个宏的定义,它有类似下面的代码:

// 在atlconv.h文件中
#define USES_CONVERSION \
int _convert; _convert; \
UINT _acp = GetACP(); _acp; \
LPCWSTR _lpw; _lpw; \
LPCSTR _lpa; _lpa

为什么它们用“int x;x;”——这种后面跟着变量的声明?

    很多人都碰到过这个令人困惑的问题,后来发现简单的答案是:禁止编译器的警告信息(warning)。如果单独有一行代码:
int x;
且从来没有使用过x,那么编译器汇报错“unreferenced local variable:x”,意思是未引用过的局部变量x,如果将警告信息的输出
调到最大。为了避免讨厌的警告,USES_CONVERSION引用声明的变量。

int x; // 声明
x; // 使用这个变量

在C++之前的时代,程序员有时在C中用函数形参做同样的事情来避免“unreferenced formal parameter”或其它的深奥费解的编译错误。

void MyFunc(int x, char y)
{
x;
y;

}

当然,现在用下面的代码可以更有效地完成同样的事情:

// 参数 x 不是用
void MyFunc(int /* x */)
{

}


 

发表于 2004-10-27 08:29 lishengg的紫罗兰茶馆 阅读(3192) | 评论 (3)编辑 收藏

Depends工具 使用说明和注意

近期很多兄弟们问怎么样打包程序,如何获取所需dll的信息,这就需要使用VC所带的Depends软件,该软件在VC6安装目录下的tools文件夹里面   D:\Microsoft Visual Studio\Common\Tools,直接
双击执行,然后打开exe文件即可,它主要有下面几个注意事项:

1)所编的软件所需的Dll文件,可以得到相应的Dll路径,版本,属性等。

2)窗口分四部分:
左上角是Dll信息窗口,显示你程序所需的Dll模块,
右边第一个窗口是所选的Dll模块所使用的函数,
右边第二个窗口是所选Dll模块的所有的导出函数,
下面窗口是所有需要的Dll模块的属性

3)右边两个窗口出现四个标签:序号,提示,函数,入口点
如果利用导出是函数,那么出现函数名,如果导出的是序号,那么函数项就是N/A(无法显示)
出现红色提示表示不正常,一般为没有该导出函数

4)该工具得到的是你软件中隐式链接的Dll库,也就是用lib关联的Dll模块,
无法显示显式链接的Dll模块,也就是用LoadLibrary函数导入的Dll函数。(切记切记!)


5)无法提供Borland C++ Builder所提供的Dll文件,无法提供vxd软件的调用

发表于 2004-10-27 08:17 lishengg的紫罗兰茶馆 阅读(3639) | 评论 (5)编辑 收藏

高效的使用watch窗口

程序调试过程中,最重要也罗嗦的就是要查看变量的值,还有GetLastError要时时执行看API执行
是否正确,下面的高效的使用watch窗口可以给各位减轻一下调试的劳动:
在watch窗口中输入下面的内容:

1) @err,hr		显示API函数调用GetLastError的返回值,和解释

2) @eax,hr		显示eax寄存器的值,由于win的API的返回值放在eax中,所以这句话就是得到最近一个API                        的返回值

3) p,***(数字)		数组指针扩展出来只有单个元素,而你又想看到全部数组元素,可以用这个技巧 

4) VC调试观察窗口的格式化符号表格

符号          格式                例子          输出
d或者i      有符号十进制整数     -42,d         -42
U           无符号十进制整数     42,d          42
O           无符号八进制整数     42,o          052 
x或X        十六进制整数         42,x           0x0000002a或0x0000002A
H           为d,I,u,o,x显示前缀  42,hx          0X002a
F           有符号浮点数         1.5,f         1.500000
E           有符号科学计数法     1.5,e          1.500000e+000
G           压缩的有符号浮点数   1.5,g          1.5
C           字符                 42,c           '*'
S           ANSI字符串           "bugs",s       "bugs"
Su          Unicode字符串        "bugs",st      "bugs"
Hr          HRESULT和Win32错误码 0X06,hr        The handle is invalid
wm          Windows消息号        0x01,wm        WM_CREATE
[digits]    显示数组元素         s,5            显示s[]前五个值
很简单吧,你调试的过程中不妨试一试,事半功倍的效果........

发表于 2004-10-27 07:59 lishengg的紫罗兰茶馆 阅读(2581) | 评论 (10)编辑 收藏