zoukankan      html  css  js  c++  java
  • 挺好玩的C语句



    挺好玩的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 */)
    {

    }

  • 相关阅读:
    软件测试工程师linux十大场景命令使用
    用yum安装软件显示错误:cannot find a valid baseurl for repo: base
    Redis安装、启动与多端口配置
    Linux vi编辑器
    cookie 和session、三种保持登陆会话的方式
    服务器内存溢出问题
    selenium多窗口切换
    Turtle库的学习积累
    高频ES6
    事件冒泡和捕获的执行顺序
  • 原文地址:https://www.cnblogs.com/huqingyu/p/201915.html
Copyright © 2011-2022 走看看