Chinaunix首页 | 论坛 | 博客
  • 博客访问: 255471
  • 博文数量: 52
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1538
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-24 07:45
个人简介

生活就像海洋,只有意志坚强的人,才能到达彼岸。

文章存档

2013年(52)

分类: C/C++

2013-09-17 20:44:14

一、const和引用疑惑

看实例代码

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     const int x = 1;
  5.     const int& rx = x;
  6.     
  7.     int& nrx = const_cast<int&>(rx);
  8.     
  9.     nrx = 5;
  10.     
  11.     printf("x = %d\n", x);
  12.     printf("rx = %d\n", rx);
  13.     printf("nrx = %d\n", nrx);
  14.     printf("x = %p\n", &x);
  15.     printf("rx = %p\n", &rx);
  16.     printf("nrx = %p\n", &nrx);

  17.     volatile const int y = 2;
  18.     int* p = NULL;

  19.     p = const_cast<int*>(&y);
  20.     *p = 6;

  21.     printf("y = %d\n", y);
  22.     printf("*p = %d\n", *p);
  23.     
  24.     const int z = y;

  25.     p = const_cast<int*>(&z);
  26.     *p = 7;

  27.     printf("z = %d\n", z);
  28.     printf("*p = %d\n", *p);

  29.     char c = 'c';
  30.     char& rc = c;
  31.     const int& trc = c;
  32.     
  33.     rc = 'a';
  34.     
  35.     printf("c = %c\n", c);
  36.     printf("rc = %c\n", rc);
  37.     printf("trc = %c\n", trc);
  38.     
  39.     return 0;
  40. }
问题:什么是符号表?符号表存储在程序中的哪个地方?

答:符号表示编译器在编译过程中产生的关于源程序中语法符号的数据结构,如常量表、变量名表、数组名表、函数名表等等;

符号表示编译器自用的内部数据结构;

符号表不会进入最终产生的可执行程序中。

只有用字面量初始化的const常量才会进入符号表:对const常量引用会导致编译器为其分配空间;虽然const常量被分配了空间,但是这个空间中的值不会被调用;使用其它的变量初始化

的const常量仍然是只读变量。


被volatile修饰的const常量不会进入符号表,退化为只读变量,每次访问都从内存中取值

const引用的类型与初始化变量的类型:

相同:使初始化变量成为只读变量

不相同:生成一个新的只读变量,其初始值与初始化变量相同。

在编译期间不能直接确定初始值的const量,都被称作为只读变量处理。

二、引用与指针的疑惑

看下面代码:

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. struct SV
  3. {
  4.     int x;
  5.     int y;
  6.     int z;
  7. };

  8. struct SR
  9. {
  10.     int& x;
  11.     int& y;
  12.     int& z;
  13. };

  14. int main()
  15. {
  16.     SV sv = {1, 2, 3};
  17.     SR sr = {sv.x, sv.y, sv.z};
  18.     
  19.     printf("&sv = %p\n", &sv);
  20.     printf("&sv.x = %p\n", &sv.x);
  21.     printf("&sv.y = %p\n", &sv.y);
  22.     printf("&sv.z = %p\n", &sv.z);
  23.     
  24.     printf("&sr = %p\n", &sr);
  25.     printf("&sr.x = %p\n", &sr.x);
  26.     printf("&sr.y = %p\n", &sr.y);
  27.     printf("&sr.z = %p\n", &sr.z);
  28.     
  29.     SV& rsv = sv;
  30.     
  31.     rsv.x = 4;
  32.     rsv.y = 5;
  33.     rsv.z = 6;
  34.     
  35.     printf("sv.x = %d\n", sv.x);
  36.     printf("sv.y = %d\n", sv.y);
  37.     printf("sv.z = %d\n", sv.z);
  38.     
  39.     return 0;
  40. }
指针与引用的区别:

指针是一个变量,其值为一个内存地址,通过指针可以访问对应内存地址中的值;

引用时一个变量的新名字,所有对引用的操作(赋值,取地址等)都会传递到其引用的变量上;

指针可以被const修饰称为常量或者只读变量;

const引用使其引用的变量具有只读属性

指针就是变量,不需要初始化,也可以指向不同的地址。

引用天生就必须在定义时初始化,之后无法在引用其它变量

问题:如何理解“引用的本质就是指针常量”?

答:从使用C++语言的角度来看:

    引用与指针常量没有任何的关系,引用时变量的新名字,操作引用就是对应的变量。

从C++编译器的角度来看:

    为了支持新概念“引用”必须要一个有效的解决方案,在编译器内部,使用指针常量来实现“引用”,因此“引用”在定义时必须初始化;

    当进行C++编程时,直接站在使用的角度看待引用,与指针毫无关系!

    当对C++程序中的一些设计引用的bug或者“奇怪行为”进行分析时,可以考虑站在C++编译器的角度看待引用!

三、重载的疑惑

看下面代码:


点击(此处)折叠或打开

  1. #include <stdio.h>

  2. void func(int a, int b)
  3. {
  4.     printf("void func(int a, int b)\n");
  5. }

  6. void func(int a, char b)
  7. {
  8.     printf("void func(int a, char b)\n");
  9. }

  10. void func(char a, int b)
  11. {
  12.     printf("void func(char a, int b)\n");
  13. }

  14. void func(char a, char b)
  15. {
  16.     printf("void func(char a, char b)\n");
  17. }

  18. int main()
  19. {
  20.     int a = 1;
  21.     char b = '2';
  22.     
  23.     func(a, a);
  24.     func(a, b);
  25.     func(b, a);
  26.     func(b, b);
  27.     
  28.     func(1, 2);
  29.     func(1 '2');
  30.     func('1', 2);
  31.     func('1', '2');
  32.     
  33.     return 0;
  34. }

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     printf("sizeof(\'1\') = %d\n", sizeof('1'));
  5.     printf("sizeof(2) = %d\n", sizeof(2));
  6.     printf("sizeof(3.0) = %d\n", sizeof(3.0));
  7.     
  8.     char c = '1';
  9.     short s = '1';
  10.     int i = '1';
  11.     long l = '1';
  12.     long long ll = '1';
  13.     
  14.     c = 2;
  15.     s = 2;
  16.     i = 2;
  17.     l = 2;
  18.     ll = 2;
  19.     
  20.     float f = 0;
  21.     double d = 0;
  22.     
  23.     f = 3.0;
  24.     d = 3.0;
  25.     
  26.     return 0;
  27. }
C++编译器对字面量的处理方式

    整数型字面量的默认类型为int,占用4个字节;

    浮点型字面量的默认类型为double,占用8个字节;

    字符型字面变量的默认类型为char,占用1个字节;

    字符串型字面量的默认类型为const char*,占用4个字节;

当使用字面量对变量进行初始化或赋值时:

无溢出产生:编译器对字面量进行默认类型转坏;

产生溢出:编译器会做截断操作,并产生警告。


深入理解重载规则:

精确匹配实参;
通过默认类型转换匹配实参;
通过默认实参匹配实参;

三条规则会同时对已存在的重载函数进行挑选:

当实参为变量并能够精确匹配形参时,不再进行默认类型转换的尝试。

当实参为字面量时,编译器会同时进行精确匹配和默认类型转换的尝试。

四、C方式的以后

看下面代码:


点击(此处)折叠或打开

  1. #include <stdio.h>

  2. extern "C"
  3. {
  4.     
  5.     void func(int x)
  6.     {
  7.         const int i = 1;
  8.         int& ri = const_cast<int&>(i);
  9.         
  10.         ri = 5;
  11.         
  12.         printf("i = %d\n", i);
  13.         printf("ri = %d\n", ri);
  14.     }

  15. }

  16. void func(const char* s)
  17. {
  18.     printf("%s\n", s);
  19. }

  20. int func(int a, int b)
  21. {
  22.     return a + b;
  23. }

  24. int main()
  25. {
  26.     func(1);
  27.     func("Delphi Tang");
  28.     func(1, 2);
  29.     
  30.     return 0;
  31. }

深入理解 extern  "C"

extern "C"告诉C++编译器将其中的代码进行C方式的编译,C方式的编译主要按照C语言的规则对函数进行编译,函数名经过编译后可能与源码中的名字有所不同;C++编译器为了支持重

载,函数名经过编译后会加上参数信息,因而编译后的函数名与源码中完全不同;C编译器不会再编译后的函数名中加上参数信息。

extern "C"中的重载函数经过C方式编译后将得到相同的函数名,因此extern “C”中不允许重载函数,但extern “C”中的函数可以与extern “C”之外的函数进行重载。


阅读(2131) | 评论(0) | 转发(0) |
0

上一篇:LCD驱动程序简介

下一篇:我从内部看ARM

给主人留下些什么吧!~~