zoukankan      html  css  js  c++  java
  • c语言宏

    使用

    c语言的宏是在预处理时候对字符进行简单替换。

    优点:1.如果要改一个变量,只需要改宏就可以了,也就是只改一次;2.宏函数展开和普通函数一样,但是它没有普通函数调用的过程,不需要压栈出栈等操作,所以效率高。

    缺点:增大了编译后可执行文件的大小

    比如常见的

    #define MAX(a,b) ((a)>(b)?(a):(b))

    变量使用括号包围,否则这样调用时

    MAX(8+3,6+1)

    结果并不是我们想要的

    即使使用括号包围了,宏依然是有陷阱的,比如这样调用

    a = 9; MAX(a++, 8)

    宏展开之后,成了这样:

    ((a++)>(8)?(a++):(8))

    a++被执行了两次

    再比如,在宏中调用了函数,那么,这个函数可能被执行了多次。

    所以,我们可以这样定义:

    #define MAX(x,y) ({ 
        typeof(x) _##x=(x); typeof(y) _##y=(y); 
        &_##x==&_##y; 
        _##x>_##y?_##x:_##y; 
    })

    gdb调试

    使用gdb调试宏的时候,加-g3选项,因为默认的-g选项,级别为2,看不到宏

    (gdb) help macro
    Prefix for commands dealing with C preprocessor macros.
    
    List of macro subcommands:
    
    macro define -- Define a new C/C++ preprocessor macro
    macro expand -- Fully expand any C/C++ preprocessor macro invocations in EXPRESSION
    macro expand-once -- Expand C/C++ preprocessor macro invocations appearing directly in EXPRESSION
    macro list -- List all the macros defined using the `macro define' command
    macro undef -- Remove the definition of the C/C++ preprocessor macro with the given name

    #

    When you put a # before an argument in a preprocessor macro, the preprocessor turns that argument into a character array
    宏定义中的#是把跟在后面的参数转换成一个字符串

    ##分割连接符

    在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。使用空格分段的话,替换之后有空格,如果我们不想要空格,可以用##分隔

    1.#define TYPE1(type,name) type name_##type##_type
    2.#define TYPE1(type,name) type name _##type##_type
    3.#define TYPE2(type,name) type name##_##type##_type

    1中,name_是一个段,其中的name没有被宏替换

    2和3中,name作为一个段,就会被宏替换。但是2中name和_之间有个空格

    宏的相互调用

    #define _STR(a) #a
    #define STR(a) _STR(a)
    #define CAT(a,b) a##b

    STR(CAT(3,5))被处理为:"35"

    _STR(CAT(3,5))被处理为:"CAT(3,5)"。因为宏替换只是进行很简单的字符替换。

    可变参数宏

    ISO C标准的可变参数宏定义,类似这个

    #define debug(format, ...) fprintf(stderr,format, __VA_ARGS__)

    对这个宏,"..."指可变参数。在展开时,"..."表示0个或多个符号,包括逗号,一直到括号结束为止。当调用时,那些符号序列将代替里面的__VA_ARGS__。
    gcc 还支持这样的语法:

    #define debug(format, args...) fprintf(stderr, format, args)

    这和上面举的那个ISO C定义的宏例子是完全一样的,但是这么写可读性更强并且更容易进行描述。

    在标准C里,你不能省略可变参数,但是你却可以给它传递一个空的参数。

    但是,下面的宏调用在ISO C里是非法的,因为字符串后面没有逗号:

    debug ("A message")

    需要写成这样:

    debug ("A message",)

    又有了新的问题,上面宏展开后,成了这样:

    fprintf(stderr, "A message", )

    为了解决这个问题,使用"##"操作,宏改为:

    #define debug(format, ...) fprintf (stderr,format, ## __VA_ARGS__)

    如果可变参数被忽略或为空,‘##'操作将使预处理器去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,GNU CPP也会工作正常,它会把这些可变参数放到逗号的后面。象其它的pasted macro参数一样,这些参数不是宏的扩展。

    一个简单的日志

    #define LOG(format, ...) 
      save_log("[%d] " format "
    ", __LINE__, ##__VA_ARGS__)
    
    void save_log(const char* format, ...)
    {
      va_list args;
    
      FILE* pf = fopen("log.txt", "a+");
    
      va_start(args, format);
      vfprintf(pf, format, args);
      va_end(args);
    
      fclose(pf);
    }

     

  • 相关阅读:
    2014.5.20知识点学习:void及void指针含义的深刻解析(转载)
    2014.5.20知识点学习:void与void*(转载)
    2014.5.19知识点学习:上下文切换
    编写“全选”按钮来操作大量复选框
    排序算法(冒泡排序,选择排序,插入排序,快速排序)
    算法基础
    Git &GitHub
    flask 上下文管理 &源码剖析
    rest-framework框架的基本组件
    Django的FBV和CB
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/9858554.html
Copyright © 2011-2022 走看看