当前所在位置:珠峰网资料 >> 计算机 >> 计算机等级考试 >> 正文
计算机二级考试C语言辅导:C语言的作用域/namespace分析
发布时间:2009/12/27 14:02:21 来源:城市学习网 编辑:海蓝

  在csdn上看到一段代码。觉得很有意思,于是便自己动动手分析分析。

  这是用于分析C语言中的作用的一段代码,值得研究研究。

  代码中calloc之后并没有free掉,这是个不好的习惯. :)

  好吧,我们从代码开始:

  原始代码

  Code

  1 #include <stdio.h>

  2 #include <stdlib.h>

  3

  4 int x(const int int_a) {return int_a;}

  5

  6 struct x

  7 {

  8     int x;

  9 };

  10

  11 #define x(x)  x

  12

  13 int main(int argc, char *argv[])

  14 {

  15     int *x = calloc(1, sizeof x);

  16

  17     x: (((struct x *)x)->x) = x(5);

  18

  19     printf("%p\n", ((struct x *)x)->x);

  20

  21     return 0;

  22 }

  23 /*

  24 output:

  25 0x5

  26 */

  [0] 变量名(包括指针名,函数名)和自定义类型名(struct)存在于不同namespace.所以b不会和a,c冲突

  Code

  1 int x(const int int_a) {return int_a;}      //a

  2

  3 struct x                                    //b

  4 {

  5     int x;

  6 };

  7

  8 #define x(x)  x

  9

  10 int main(int argc, char *argv[])

  11 {

  12     int *x = calloc(1, sizeof x);           //c

  13

  14     x: (((struct x *)x)->x) = x(5);

  15

  16     printf("%p\n", ((struct x *)x)->x);

  17

  18     return 0;

  19 } [NextPage]

  [1] (int *)x和(int *(const int))x不在同一层namespace,编译通过.

  链接时出错.(int *)x将(int *(const int))x覆盖,所以在c行时会找不到匹配的函数名

  Code

  1 int x(const int int_a) {return int_a;}   //a

  2

  3 struct x

  4 {

  5     int x;

  6 };

  7

  8 //#define x(x)  x

  9

  10 int main(int argc, char *argv[])

  11 {

  12     int *x = calloc(1, sizeof x);        //b

  13

  14     x: (((struct x *)x)->x) = x(5);      //c

  15

  16     printf("%p\n", ((struct x *)x)->x);

  17

  18     return 0;

  19

  [2] 编译通过

  Code

  1 int x(const int int_a) {return int_a;}

  2

  3 struct x

  4 {

  5     int x;

  6 };

  7

  8 //#define x(x)  x

  9

  10 int main(int argc, char *argv[])

  11 {

  12     int *x = calloc(1, sizeof x);

  13

  14     //x: (((struct x *)x)->x) = x(5);

  15

  16     //printf("%p\n", ((struct x *)x)->x);

  17

  18     return 0;

  19 }

  20

  [3] 编译出错.(int *)x和(int *(const int))x在同一层namespace,冲突.

  1 int x(const int int_a) {return int_a;}

  2

  3 int *x;

  4

  5 int main(int argc, char *argv[])

  6 {

  7     return 0;

  8 }

  9[NextPage]

  [4] #define在预编译阶段替换其后面代码,所以对#define后面的代码来说,x(n)被替换为n,所以在编译时代码会扩展为如下:

  Code

  1 int x(const int int_a) {return int_a;}

  2

  3 struct x

  4 {

  5     int x;

  6 };

  7

  8 #define x(x)  x

  9

  10 int main(int argc, char *argv[])

  11 {

  12     int *x = calloc(1, sizeof x);

  13

  14     x: (((struct x *)x)->x) = 5;         //x(5)替换为5,所以并没有调用函数int x(const int)

  15

  16     printf("%p\n", ((struct x *)x)->x);

  17

  18     return 0;

  19 }

  关于标签label.

  标签,仅仅是一个符号,存在一个label专用的namespace,仅对goto可见,所以不会与变量或者常量冲突.

  在MSDN的goto条目中也有相关的描述:

  "The set of identifier names following a goto has its own name space so the names do not interfere with other identifiers. Labels cannot be redeclared."

  Code

  1 int main(int argc, char *argv[])

  2 {

  3     int p = 5;

  4

  5     x: printf("line x.\n");

  6

  7     ++p;

  8

  9     if (p == 8) return 0;

  10

  11     goto x;

  12 }

  13

  14 int main(int argc, char *argv[])

  15 {

  16     int x = 5;

  17

  18     x: printf("label x.\n");          //这里的label x与(int)x是无关的

  19

  20     ++x;

  21

  22     if (x == 8) return 0;

  23

  24     goto x;                          //goto会在标签namespace查找label x.

  25

  26     printf("x = %d | :( .\n", x); //无效语句

  27     return 0;                     //无效语句

  28 } [NextPage]

  [5] 所以代码中label x与其他命名不冲突

  Code

  1 int x(const int int_a) {return int_a;}

  2

  3 struct x

  4 {

  5     int x;

  6 };

  7

  8 #define x(x)  x

  9

  10 int main(int argc, char *argv[])

  11 {

  12     int *x = calloc(1, sizeof x);

  13

  14     x: (((struct x *)x)->x) = x(5);         //这里的label x存在于独立的namespace,与其他不冲突.

  15

  16     printf("%p\n", ((struct x *)x)->x);

  17

  18     return 0;

  19 }

  [6] 现在我们把代码中无效代码去掉,并把宏定义语句手动替换掉,是的代码简洁点

  Code

  1 struct x

  2 {

  3     int x;

  4 };

  5

  6 int main(int argc, char *argv[])

  7 {

  8     int *x = calloc(1, sizeof(int *));

  9

  10     //到此我们有自定义类型struct x和变量(int *)x,其中struct x作用域为全局,(int *)x作用域为main()

  11

  12     (((struct x *)x)->x) = 5;

  13     //            ↑

  14     //           这里的x是由(int *)强制转化成(struct x *),所以后面实际是给struct中的(int)x赋值

  15

  16     printf("%p\n", ((struct x *)x)->x);   //这里还是需要强制转化成struct,这样才能识别,然后得到(int)x的值

  17

  18     return 0;

  19 }

  到此代码中所有的x都说明了,这里再次总结下.

  Code

  1 #include <stdio.h>

  2 #include <stdlib.h>

  3

  4 int x(const int int_a) {return int_a;}      //全局的函数名

  5

  6 struct x                                    //全局的struct名,属于自定义类型名,所以不会跟上面的(int *(const int))x及下面main中的(int *)x冲突

  7 {

  8     int x;                                  //属于struct x的int型x

  9 };

  10

  11 #define x(x)  x                             //宏定义,会在预编译时进行代码扩展,所以并不会在编译时产生命名冲突

  12

  13 int main(int argc, char *argv[])

  14 {

  15     int *x = calloc(1, sizeof x);           //作用域为main的(int *)x; sizeof计算的是(int *)x大小.

  16

  17     x: (((struct x *)x)->x) = x(5);         //作为label的x独立存在于一个namespace.

  18

  19     printf("%p\n", ((struct x *)x)->x);

  20

  21     return 0;

  22 }

广告合作:400-664-0084 全国热线:400-664-0084
Copyright 2010 - 2017 www.my8848.com 珠峰网 粤ICP备15066211号
珠峰网 版权所有 All Rights Reserved