预处理
预处理器标识#error的目的是什么?
#error预处理指令的作用是,编译程序时,只要遇到#error就会生成一个编译错误提示消息,并停止编译。其语法格式为:#error error-message。
下面举个例子:
程序中往往有很多的预处理指令
#ifdef XXX …
#else
#endif
当程序比较大时,往往有些宏定义是在外部指定的(如makefile),或是在系统头文件中指定的,当不太确定当前是否定义了 XXX 时,就可以改成如下这样进行编译:
#ifdef XXX …
#error “XXX has been defined”
#else
#endif
这样,如果编译时出现错误,输出了XXX has been defined,表明宏XXX已经被定义了。
定义常量谁更好?#define还是const?
define与 const都能定义常量,效果虽然一样,但是各有侧重。
define既可以替代常数值,又可以替代表达式,甚至是代码段,但是容易出错,而 const的引入可以增强程序的可读性,它使程序的维护与调试变得更加方便。具体而言,它们的差异主要表现在以下3个方面。
- define只是用来进行单纯的文本替换, define常量的生命周期止于编译期,不分配内存空间,它存在于程序的代码段,在实际程序中,它只是一个常数;而 const常量存在于程序的数据段,并在堆栈中分配了空间, const常量在程序中确确实实存在,并且可以被调用、传递。
- const常量有数据类型,而 define常量没有数据类型。编译器可以对 const常量进行类型安全检
査,如类型、语句结构等,而 define不行。 - 很多IDE支持调试 const定义的常量,而不支持 define定义的常量由于 const修饰的变量可以排除程序之间的不安全性因素,保护程序中的常量不被修改,而且对数据类型也会进行相应的检查,极大地提高了程序的健壮性,所以一般更加倾向于用const来定义常量类型。
typedef和define有什么区别?
typedef 与 define 都是替一个对象取一个别名,以此来增强程序的可读性,但是它们在使用和作用上也
存在着以下4个方面的不同。
- 原理不同
#define是C语言中定义的语法,它是预处理指令,在预处理时进行简单而机械的字符串替换,不做正确性检査,不管含义是否正确照样代入,只有在编译已被展开的源程序时,才会发现可能的错误并报错。例如, # define Pl 3.1415926 ,当程序执行 area=PI*r*r 语句时,PI会被替换为3.1415926。于是该
语句被替换为 area=3.1415926*r*r 。如果把# define语句中的数字9写成了g,预处理也照样代入,而不去检查其是否合理、合法。
typedef是关键字,它在编译时处理,所以 typedef具有类型检查的功能。它在自己的作用域内给一个已经存在的类型一个别名,但是不能在一个函数定义里面使用标识符 typedef。例如, typedef int INTEGER; ,这以后就可用 INTEGER来代替int作整型变量的类型说明了,例如: INTEGER a,b;
用 typedef定义数组、指针、结构等类型将带来很大的方便,不仅使程序书写简单而且使意义更为明确,因而增强了可读性。例如: typedef int a[10];表示a是整型数组类型,数组长度为10。然后就可用a说明变量,例如:语句a s1,s2;完全等效于语句 int s1[10],s2[10]。同理, typedef void(*p)(void)表示p是一种指向void型的指针类型。
- 功能不同
typedef用来定义类型的别名,这些类型不仅包含内部类型(int、char等),还包括自定义类型(如struct),可以起到使类型易于记忆的功能。
例如: typedef int (*PF)(const char *, const char*);
定义一个指向函数的指针的数据类型PF,其中函数返回值为int,参数为 const char*。typedef还有另外一个重要的用途,那就是定义机器无关的类型。例如,可以定义一个叫REAL的浮点类型,在目标机器上它可以获得最高的精度: typedef long double REAL; ,在不支持 long double的机器上,该 typedef看起来会是下面这样: typedef double REAL; ,在 double都不支持的机器上,该 typedef看起来会是这样: typedef float REAL; 。
#define不只是可以为类型取别名,还可以定义常量、变量、编译开关等。
- 作用域不同
#define没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用,而 typedef有自己的作用域。
程序示例如下:
void fun()
{
#define A int
}
void gun()
{
//这里也可以使用A,因为宏替换没有作用域,但如果上面用的是 typedef,那这里就不能用
//A,不过,一般不在函数内使用 typedef
}
- 对指针的操作不同
两者修饰指针类型时,作用不同。
#define INTPTR1 int*
typedef int* INTPTR2;
INTPTR1 p1,p2;
INTPTR2 p3,p4;
INTPTR1 p1, p2和INTPTR2 p3, p4的效果截然不同。 INTPTR1 p1, p2进行字符串替换后变成int*p1,p2 ,要表达的意义是声明一个指针变量p1和一个整型变量p2.而 INTPTR2 p3,p4,由于INTPTR2是具有含义的,告诉我们是一个指向整型数据的指针,那么p3和p4都为指针变量,这句相当于int*pl,*p2 。从这里可以看出,进行宏替换是不含任何意义的替换,仅仅为字符串替换;而用 typedef为一种数据类型起的别名是带有一定含义的。
程序示例如下:
#define INTPTR1 int*
typedef int* INTPTR2
int a=1;
int b=2;
int c=3;
const INTPTR1 p1=&a;
const INTPTR2 p2=&b;
INTPTR2 const p3=&c;
上述代码中, const INTPTR1 p1表示p1是一个常量指针,即不可以通过p1去修改p1指向的内容,但是p1可以指向其他内容。而对于 const INTPTR2 p2,由于 INTPTR2表示的是个指针类型,因此用 const去限定,表示封锁了这个指针类型,因此p2是一个指针常量,不可使p2再指向其他内容,但可以通过p2修改其当前指向的内容。 INTPTR2 const p3同样声明的是一个指针常量。
如何使用define声明一个常数,用以表明一年中有多少秒?(忽略闰年问题)
#define SECOND_PER_YEAR (606024*365)UL
#include <filename.h> 和 #include “filename.h” 有什么区别?
对于 include< filename. h>,编译器先从标准库路径开始搜索 filename.h,使得系统文件调用较快。
对于# include“ filename.h"”,编译器先从用户的工作路径开始搜索 filename.h,然后去寻找系统路径,使得自定义文件较快。
头文件的作用有哪些?
头文件的作用主要表现为以下两个方面:
- 通过头文件来调用库功能。出于对源代码保密的考虑,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口是怎么实现的。编译器会从库中提取相应的代码。
- 头文件能加强类型安全检查。当某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,大大减轻程序员调试、改错的负担。
在头文件中定义静态变量是否可行,为什么?
不可行,如果在头文件中定义静态变量,会造成资源浪费的问题,同时也可能引起程序错误。因为如果在使用了该头文件的每个C语言文件中定义静态变量,按照编译的步骤,在每个头文件中都会单独存在一个静态变量,从而会引起空间浪费或者程序错误。所以,不推荐在头文件中定义任何变量,当然也包括静态变量。
写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个?
#define MIN(A,B) ( (A) <= (B) ? (A) : (B) )
&spm=1001.2101.3001.5002&articleId=158348154&d=1&t=3&u=d969b5a020b842e8b6d257b146322e2e)
1016

被折叠的 条评论
为什么被折叠?



