《c专家编程》学习笔记(一)

1、typedef和#define的区别

1、typedef:

typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间。

可以增强程序的可读性,以及标识符的灵活性。

2、#define:

#define宏定义语句,是预处理指令。通常用来定义常量(包括无参量与带参量)。它本身并不在编译过程中进行,而是在这之前(预处理过程)就已经完成了,但也因此难以发现潜在的错误及其它代码维护问题。

3、区别:

(1)typedef在编译阶段有效,由于是在编译阶段,因此typedef有类型检查的功能。#define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的字符串替换,而不进行任何检查
(2)宏定义只是简单的字符串代换(原地扩展),而typedef则不是原地扩展,它的新名字具有一定的封装性,以致于新命名的标识符具有更易定义变量的功能。在连续几个变量的声明中,用typedef定义的类型能保证声明中所有的变量均为同一种类型,而用#define定义的类型无法保证。如下所示:

typedef    int*   pINT;
#define pINT2 int*

效果完全不同!
pINT a,b;的效果与int *a; int *b;相同,表示定义了两个整型指针变量。而pINT2 a,b;的效果与int *a, b;相同,表示定义了一个整型指针变量a和整型变量b。

因此,typedef可以用作同时声明指针型的多个对象,形式直观。

(3)作用域不同。#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用。而typedef有自己的作用域。

Effective C++一书中有关于#define的分析:
(1)对于单纯常亮,最好以const对象或enums替换#define。
(2)对于形似函数的宏,最好改用inline函数替换#define。

2、数组和指针并不相同

1、定义和声明

(1)定义:只能出现在一个地方; 确定对象的类型并分配内存,用于创建新的对象。如:int my_array[100];
(2)声明:可以多次出现; 描述对象的类型,用于指代其他地方定义的对象。如:extern int my_array[];

C语言中的对象必须有且只有一个定义,但它可以有多个extern声明。

2、指针和数组是如何访问的

(1)对数组的访问:对内存直接的引用。每个符号的地址在编译时可知。所以,如果编译器需要一个地址(可能还需要加上偏移量)来执行某种操作,它就可以直接进行操作,并不需要增加指令首先取得具体的地址。

这也说明了为什么extern char a[]与extern char a[100]等价。这两个声明都指明 a 是一个数组,也就是一个内存地址。编译器并不知道数组有多长,因为它只产生偏离其实地址的偏移地址。从数组提取一个字符,只要简单地从符号表显示的 a 的地址加上下标,需要的字符就位于这个地址中。

(2)对指针的引用:对内存间接的引用。必须首先在运行时取得它的当前值,然后才能对它进行解除引用操作(作为以后进行查找的步骤之一)。

也就是说,如果声明 extern char *p,它告诉编译器 p 是一个指针,它指向的对象是一个字符。为了取得这个字符,必须得到地址 p 的内容,把它作为字符的地址并从这个地址中取得这个字符。指针的访问需要增加一次额外的提取。

3、当你“定义为指针,但以数组方式引用”时会发生什么

例如:

char *p="abcdefgh";
c=p[i];

(本来针对数组)需要对内存进行直接的引用,但是编译器所执行的却是对内存进行间接引用(因为定义的是指针)。实质是指针和数组两种访问方式的组合,编译器执行的过程:
(1)取得符号表中p的地址,提取存储于此处的指针。
(2)把下标所表示的偏移量与指针的值(内容为字符串的地址)相加,产生一个地址。
(3)访问上面这个地址,取得字符。

你可能感兴趣的:(《c专家编程》学习笔记(一))