Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1788697
  • 博文数量: 335
  • 博客积分: 4690
  • 博客等级: 上校
  • 技术积分: 4341
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-08 21:38
个人简介

无聊之人--除了技术,还是技术,你懂得

文章分类

全部博文(335)

文章存档

2016年(29)

2015年(18)

2014年(7)

2013年(86)

2012年(90)

2011年(105)

分类: C/C++

2012-12-19 18:42:56

macro看似只进行简单的文本替换,在预处理阶段它会根据你所定义的macro生成一个hash,稍后再处理的时候,根据遇到的macro名查找hash,得到宏的内容,使用hash存储速度非常快。
下面我们进行一个简单的实验,猜猜程序的运行结果?
macro.c

点击(此处)折叠或打开

  1. #include <assert.h>
  2. #define WIDTH 40
  3. #define HEIGHT 80
  4. #define AREA 2*(WIDTH* HEIGHT)
  5. #define MAX(a,b) ( ((a) > (b))?(a): (b))
  6. int main(int argc,char ** argv){
  7.     int i=1;
  8.     int j=2;
  9.     int c;
  10.     c = MAX(i ,j );
  11.     assert(j == 4);
  12.     assert( AREA == 6400);
  13. }
after post preprocessor:
我们观察一下程序预处理后的信息
gcc -E macro.c > macro.i

点击(此处)折叠或打开

  1. # 1 "macro.c"
  2. # 1 ""
  3. # 1 ""
  4. # 1 "macro.c"
  5. # 1 "/usr/include/assert.h" 1 3 4
  6. # 37 "/usr/include/assert.h" 3 4
  7. # 1 "/usr/include/features.h" 1 3 4
  8. # 323 "/usr/include/features.h" 3 4
  9. # 1 "/usr/include/i386-linux-gnu/bits/predefs.h" 1 3 4
  10. # 324 "/usr/include/features.h" 2 3 4
  11. # 356 "/usr/include/features.h" 3 4
  12. # 1 "/usr/include/i386-linux-gnu/sys/cdefs.h" 1 3 4
  13. # 353 "/usr/include/i386-linux-gnu/sys/cdefs.h" 3 4
  14. # 1 "/usr/include/i386-linux-gnu/bits/wordsize.h" 1 3 4
  15. # 354 "/usr/include/i386-linux-gnu/sys/cdefs.h" 2 3 4
  16. # 357 "/usr/include/features.h" 2 3 4
  17. # 388 "/usr/include/features.h" 3 4
  18. # 1 "/usr/include/i386-linux-gnu/gnu/stubs.h" 1 3 4



  19. # 1 "/usr/include/i386-linux-gnu/bits/wordsize.h" 1 3 4
  20. # 5 "/usr/include/i386-linux-gnu/gnu/stubs.h" 2 3 4


  21. # 1 "/usr/include/i386-linux-gnu/gnu/stubs-32.h" 1 3 4
  22. # 8 "/usr/include/i386-linux-gnu/gnu/stubs.h" 2 3 4
  23. # 389 "/usr/include/features.h" 2 3 4
  24. # 38 "/usr/include/assert.h" 2 3 4
  25. # 68 "/usr/include/assert.h" 3 4



  26. extern void __assert_fail (__const char *__assertion, __const char *__file,
  27.       unsigned int __line, __const char *__function)
  28.      __attribute__ ((__nothrow__)) __attribute__ ((__noreturn__));


  29. extern void __assert_perror_fail (int __errnum, __const char *__file,
  30.       unsigned int __line,
  31.       __const char *__function)
  32.      __attribute__ ((__nothrow__)) __attribute__ ((__noreturn__));




  33. extern void __assert (const char *__assertion, const char *__file, int __line)
  34.      __attribute__ ((__nothrow__)) __attribute__ ((__noreturn__));



  35. # 2 "macro.c" 2




  36. int main(int argc,char ** argv){
  37.  int i=1;
  38.  int j=2;
  39.  int c;
  40.  c = ( ((i ) > (j ))?(i ): (j ));
  41.  ((j == 4) ? (void) (0) : __assert_fail ("j !== 4", "macro.c", 11, __PRETTY_FUNCTION__));
  42.  ((2*(40 *80) == 6400) ? (void) (0) : __assert_fail ("2*(40 *80) == 6400", "macro.c", 12, __PRETTY_FUNCTION__));
  43. }
需要注意的是在宏扩展以后,asser宏已经被替换成了真正的条件表达式,不过该条件表达是比较奇怪,

点击(此处)折叠或打开

  1. assert( j == 4)
  2. expand
  3. ((j == 4) ? (void) (0) : __assert_fail ("j == 4", "macro.c", 11, __PRETTY_FUNCTION__));
?表达式的条件部分很好立即,
条件结果为真是,执行的空操作 (void) (0) 这里看起来比较奇怪,其实也就是一个空操作
条件结果为假时   执行如下操作:

点击(此处)折叠或打开

  1. __assert_fail ("j == 4", "macro.c", 11, __PRETTY_FUNCTION__)
该函数在宏扩展以后,我们已经看到了该函数的prototype,
compile and link  and then run
对该程序进行编译,运行发现程序运行正常。
那C的结果为什么是4而不是3呢?这正是macro的诡异之处,
通过观察macro展开的代码不难发现

点击(此处)折叠或打开

  1. c = ( ((i ) > (j ))?(i ): (j ));
不论那一个条件为真,较大的值都执行了两次自加操作,因此J的结果为4而不是3,
这一点要求我们在对两个函数的返回结果进行比较时要注意,
两个函数比较大小,函数总共执行3次,函数的大小对你程序的性能影响还是比较大的。
note
下面附上ASSERT.H的实现,感兴趣的筒子可以看一下。
something about assert.h

点击(此处)折叠或打开

  1. /* Copyright (C) 1991,1992,1994-2001,2003,2004,2007
  2.    Free Software Foundation, Inc.
  3.    This file is part of the GNU C Library.

  4.    The GNU C Library is free software; you can redistribute it and/or
  5.    modify it under the terms of the GNU Lesser General Public
  6.    License as published by the Free Software Foundation; either
  7.    version 2.1 of the License, or (at your option) any later version.

  8.    The GNU C Library is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11.    Lesser General Public License for more details.

  12.    You should have received a copy of the GNU Lesser General Public
  13.    License along with the GNU C Library; if not, write to the Free
  14.    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  15.    02111-1307 USA. */

  16. /*
  17.  *    ISO C99 Standard: 7.2 Diagnostics    <assert.h>
  18.  */

  19. #ifdef    _ASSERT_H

  20. # undef    _ASSERT_H
  21. # undef    assert
  22. # undef __ASSERT_VOID_CAST

  23. # ifdef    __USE_GNU
  24. # undef assert_perror
  25. # endif

  26. #endif /* assert.h    */

  27. #define    _ASSERT_H    1
  28. #include

  29. #if defined __cplusplus && __GNUC_PREREQ (2,95)
  30. # define __ASSERT_VOID_CAST static_cast
  31. #else
  32. # define __ASSERT_VOID_CAST (void)
  33. #endif

  34. /* void assert (int expression);

  35.    If NDEBUG is defined, do nothing.
  36.    If not, and EXPRESSION is zero, print an error message and abort. */

  37. #ifdef    NDEBUG

  38. # define assert(expr)        (__ASSERT_VOID_CAST (0))

  39. /* void assert_perror (int errnum);

  40.    If NDEBUG is defined, do nothing. If not, and ERRNUM is not zero, print an
  41.    error message with the error text for ERRNUM and abort.
  42.    (This is a GNU extension.) */

  43. # ifdef    __USE_GNU
  44. # define assert_perror(errnum)    (__ASSERT_VOID_CAST (0))
  45. # endif

  46. #else /* Not NDEBUG. */

  47. #ifndef _ASSERT_H_DECLS
  48. #define _ASSERT_H_DECLS
  49. __BEGIN_DECLS

  50. /* This prints an "Assertion failed" message and aborts. */
  51. extern void __assert_fail (__const char *__assertion, __const char *__file,
  52.              unsigned int __line, __const char *__function)
  53.      __THROW __attribute__ ((__noreturn__));

  54. /* Likewise, but prints the error text for ERRNUM. */
  55. extern void __assert_perror_fail (int __errnum, __const char *__file,
  56.                  unsigned int __line,
  57.                  __const char *__function)
  58.      __THROW __attribute__ ((__noreturn__));


  59. /* The following is not at all used here but needed for standard
  60.    compliance. */
  61. extern void __assert (const char *__assertion, const char *__file, int __line)
  62.      __THROW __attribute__ ((__noreturn__));


  63. __END_DECLS
  64. #endif /* Not _ASSERT_H_DECLS */

  65. # define assert(expr)                            \
  66.   ((expr)                                \
  67.    ? __ASSERT_VOID_CAST (0)                        \
  68.    : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION))

  69. # ifdef    __USE_GNU
  70. # define assert_perror(errnum)                        \
  71.   (!(errnum)                                \
  72.    ? __ASSERT_VOID_CAST (0)                        \
  73.    : __assert_perror_fail ((errnum), __FILE__, __LINE__, __ASSERT_FUNCTION))
  74. # endif

  75. /* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__'
  76.    which contains the name of the function currently being defined.
  77.    This is broken in G before version 2.6.
  78.    C9x has a similar variable called __func__, but prefer the GCC one since
  79.    it demangles C function names. */
  80. # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4)
  81. # define __ASSERT_FUNCTION    __PRETTY_FUNCTION__
  82. # else
  83. # if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
  84. # define __ASSERT_FUNCTION    __func__
  85. # else
  86. # define __ASSERT_FUNCTION    ((__const char *) 0)
  87. # endif
  88. # endif

  89. #endif /* NDEBUG. */
通过下面这个实验你可能还会进步一的了解macro的本质,

点击(此处)折叠或打开

  1. ubuntu@ubuntu-virtual-machine:~/Desktop/detail$ cat a.h
  2. int a(int * a,int * b);
  3. ubuntu@ubuntu-virtual-machine:~/Desktop/detail$ cat b.h
  4. int b(int * a,int b) ;
  5. ubuntu@ubuntu-virtual-machine:~/Desktop/detail$ cat c.h
  6. int c(int a,int * b);
  7. ubuntu@ubuntu-virtual-machine:~/Desktop/detail$ cat ma.c
  8. #include "a.h"
  9. #include "b.h"
  10. #include "c.h"
  11. int main(int argc,char * argv]){
  12.     return 0;
  13. }

点击(此处)折叠或打开

  1. ubuntu@ubuntu-virtual-machine:~/Desktop/detail$ gcc -E ma.c
  2. # 1 "ma.c"
  3. # 1 ""
  4. # 1 ""
  5. # 1 "ma.c"
  6. # 1 "a.h" 1
  7. int a(int * a,int * b);
  8. # 2 "ma.c" 2
  9. # 1 "b.h" 1
  10. int b(int * a,int b) ;
  11. # 3 "ma.c" 2
  12. # 1 "c.h" 1
  13. int c(int a,int * b);
  14. # 4 "ma.c" 2
  15. int main(int argc,char * argv]){
  16.  return 0;
  17. }







阅读(1708) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~