灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2500回复:0

c语言中的#与##的用法简介

楼主#
更多 发布于:2012-09-06 12:31


 本文主要讲述C语言的一点基础语法和在内核的应用中其中的一点例子。
  #,##分别在C语言中是怎么作用?
  文章代码编译的环境:
  桌面环境:Ubuntu 10.04
  内核:linux 2.6.32
  编译器:gcc 4.4.3
  一、基本的用法
  1、#.参数名以#作为前缀则结果将被扩展为由实际参数的带引号的字符串。
  如:
  #define dprint(expr) printf(#expr " = %dn", expr);
  int main()
  {
  int a = 20, b = 10;
  dprint(a/b);
  return 0;
  }
  上面的例子会打印出:
  a/b = 2
  2、##.预处理器运算符##为宏提供了一种连接实际参数的手段。如果替换文本中的参数与##相邻,则该参数将被实际参数替换,##与前后的空白将被删除,并对替换后的结果重新扫描。
  形成一个新的标号,如果这样产生的记号无效,或者结果依赖于##运算顺序,则结果没有定义。
  如:
  #define paste(front, back) front ## back
  因此,宏调用paste(name, 1)的结果为name1.
  如:
  #define createfun(name1, name2)
  void name1 ## name2()
  {
  printf("%s calledn", __FUNCTION__);
  }
  createfun(the, function);
  int main()
  {
  thefunction();
  return 0;
  }
  输出的结果是:thefunction called
  二、##可以嵌套吗?
  看下面的例子:
  #define cat(x, y) x##y
  宏调用cat(var, 123)讲生成var 123.
  但是,宏调用cat(cat(1,2),3)没有定义:##阻止了外层调用的参数的扩展。因此,它将生成下列的记号串:
  cat (1,2)3.
  如果要再引入第二层的宏定义,如下定义:
  #define xcat(x, y) cat(x,y)
  那么xcat(xcat(1, 2), 3)将生成123,这是因为xcat自身的扩展不包含##运算符。
  三、linux内核中例子
  因为是做mips架构的,所以以mips为例子。
  Linux 2.6.25 内核, include/asm-mips/io.h文件。拷贝一部分的代码出来。
  #define __BUILD_MEMORY_SINGLE(pfx, bwlq, type, irq)
  
  static inline void pfx##write##bwlq(type val,
  volatile void __iomem *mem)
  {
  volatile type *__mem;
  type __val;
  
  __mem = (void *)__swizzle_addr_##bwlq((unsigned long)(mem));
  
  __val = pfx##ioswab##bwlq(__mem, val);
  
  if (sizeof(type) != sizeof(u64) || sizeof(u64) == sizeof(long))
  *__mem = __val;
  /*在这里省略了一些代码*/
  }
  #define __BUILD_MEMORY_PFX(bus, bwlq, type)
  
  __BUILD_MEMORY_SINGLE(bus, bwlq, type, 1)
  #define BUILDIO_MEM(bwlq, type)
  
  __BUILD_MEMORY_PFX(__raw_, bwlq, type)
  __BUILD_MEMORY_PFX(, bwlq, type)
  __BUILD_MEMORY_PFX(__mem_, bwlq, type)
  BUILDIO_MEM(b, u8)
  BUILDIO_MEM(w, u16)
  BUILDIO_MEM(l, u32)
  BUILDIO_MEM(q, u64)
  跟踪宏的展开。
  BUILDIO_MEM(b, u8)
  BUILDIO_MEM(w, u16)
  BUILDIO_MEM(l, u32)
  BUILDIO_MEM(q, u64)
  就会生成了如下四个函数:
  static inline void writeb(u8 val, volatile void __iomem *mem) {……}
  static inline void writew(u16 val, volatile void __iomem *mem) {……}
  static inline void writel(u32 val, volatile void __iomem *mem) {……}
  static inline void writeq(u64 val, volatile void __iomem *mem) {……}
  同时,如果当我们用函数类似writeb之类的出现了问题,一般情况下用编辑工具是找不到函数定义的,于是乎跟踪不是去了,其实不然,可以针对里面的关键字,譬如:write.是可以找到的(在linux下面用find,grep,或者是vim的配置,都可以找到)。
  是的,内核代码有时候这样的调试法……


喜欢0 评分0
游客

返回顶部