Linux C语言:#define和typedef

一、预处理指令#define

#define叫做宏定义,语法格式:
#define 名字 值
#define PI 3.14159
  • 结尾没有分号;
  • 和#include一样,在预处理阶段执行,文本替换
  • 值可以是数字、表达式、代码语句等
  • 宏定义的好处,便于程序的阅读和维护
#define MAX 50
#define M 3+2
#define N (3+2)
#define NULL 0
#define EOF -1
#define ERROR -1

  • 定义一个宏名字之后,可以在其他宏定义中使用,例如 
#define ONE 1
#define TWO ONE+ONE
#define THREE ONE+TWO

 二、没有值的宏定义

  • #include是一个预处理指令,预处理这个动作发生在编译之前:
  • #include 的作用是,在预处理时,将文件中的全部文本内容复制粘贴到#include所在的位置 

1、#define 名字 

 这种宏定义,是用于条件编译的,配合其它的预处理指令来检测这个宏是否被定义过

#define DEBUG
#ifdef DEBUG
printf("%s:This error is in \"%s\" on line %d.\n", __FUNCTION__, ___FILE___, ___LINE___);
#endif

 当运行时,这三个宏分别能返回所在的函数,所在的文件名和所在的行号。

2、#include预处理指令 

 1)<>和””有什么区别
#include <stdio.h>
#include “head.h”
  • 使用尖括号<>,编译器会到标准库路径下查找头文件/usr/include
  • 使用双引号””,编译器首先在当前目录下查找头文件,如果没有找到,再到标准库路径下查找
2)规范用法
  • 标准库的头文件使用尖括号<>
  • 自定义的头文件使用双引号”” 
3)宏定义指令 
#define、#undef

三、宏定义和 const 常量区别

 1、 定义的区别

  • 宏用 #define 声明,const 常量用 const + 数据类型 声明。
  • 宏最后没用分号,const 常量声明需要用分号表示语句结束。
  • 宏不需要用等号赋值,cosnt 常量需要用等号赋值。

2 、处理阶段阶段的不同 

  • 宏定义在预处理阶段进行文本替换。
  • const 常量在程序运行时使用。

3 、存储方式不同 

  • 宏定义是直接替换,不会分配内存,存储于程序的代码段中。
  • const 常量需要进行内存分配。 

4 、是否进行类型检查 

  • 宏定义是字符替换,不进行类型检查。
  • const 常量定义时需要声明数据类型,使用时会进行类型检测。

5 、宏定义可以声明函数

6、定义后能否取消 

  • 宏定义可以通过#undef来使之前的宏定义失效
  • const常量定义后将在定义域内永久有效
    void f1()
    {
    #define N 12
    const int n = 12;
    #undef N //取消宏定义后,即使在f1函数中,N也无效了
    #define N 21//取消后可以重新定义
    }

四、typedef的用法

1、 什么是typedef

  • typedef是在C和C++编程语言中的一个关键字。作用是为现有的数据类型(int、float、char......)创建一个新的名字
  • 目的是为了使代码方便阅读和理解。

2、 typedef用法

1)对于数据类型使用
typedef int Integer;
  • 以上就是给int起了一个新的名字Integer,注意要加分号。当要定义int类型数据时就可以:
Integer num;
  • 此时Integer num 等同于 int num。
 2)对于指针的使用
typedef int * PTRINT;
  • 以上就是给int *起了一个新的名字NEW_INT。可定义int类型指针变量如:
PTRINT x;
  • 此时PTRINT x等同于int *x。
 3)对于结构体的使用
  • 在声明结构体时可为结构体和结构体指针起别名,如: 
typedef struct NUM
{
int a;
int b;
}DATA,*PTRDATA;
  • 此时DATA等同于struct NUM,PTRDATA等同于struct NUM *。

3、进阶typedef 

1)数组指针 
int (*ptr)[3];
使用Typedef:
typedef int (*PTR_TO_ARRAY)[3];

举个栗子:

#include <stdio.h>
typedef int (*ptr_to_arr)[3];
int main(int argc, const char *argv[]) {
int i;
int temp[3] = {1, 5, 8};
ptr_to_arr p;
p = &temp;
for (i = 0; i < 3; i++) {
printf("%d\n", (*p)[i]);
}
return 0;
}
2)函数指针
int (*fun)(int);
使用Typedef:
typedef int (*PTR_TO_FUN)(int);

 举个栗子:

#include <stdio.h>
typedef int (*ptr_to_fun)(int);
int fun(int n) {
int i, sum = 0;
for (i = 1; i <= n; i++) {
sum += i;
}
return sum;
}
int main(int argc, const char *argv[]) {
ptr_to_fun p;
p = fun;
printf("%d\n", (*p)(100));
return 0;
}

五、#define和typedef的比较

 1、语法形式不同

  • typedef 是 C语言的关键字,用于创建类型别名,它需要使用标识符和现有的类型进行配合;
  • #define 是预处理指令,用于创建宏定义,它可以定义任意的标识符和文本替换。
  • 【注意】typedef 定义是语句,因为句尾要加上分号,而 #define不是语句,千万不能在句尾加分号。 

2、执行时间不同 

  • 关键字typedef在编译阶段有效,有类型检查的功能。
  • #define则是宏定义,发生在预处理阶段,也就是编译之前,它只进行简单而机械的文本替换,而不进行任何检查。

3、#define和typedef的比较 

typedef int *PTR;
PTR a,b;
此时a,b都是指针变量。

#define PTR int*
PTR a,b;
此时等同于
int *a,b;
只有a为指针变量,而b为整型变量。

4、作用域不同

1)typedef 有作用域限定

  • 如果放在所有函数之外,它的作用域就是从它定义开始直到文件尾;
  • 如果放在某个函数内,定义域就是从定义开始直到该函数结尾;

2)#define 不受作用域约束,只要是在 #define声明后的引用都是正确的

  • 不管是在某个函数内,还是在所有函数之外,作用域都是从定义开始直到整个文件结尾。 
#include <stdio.h>
//typedef int (*ptr_to_fun)();
int fun(int n) {
    #define uchar unsigned char
    typedef int (*ptr_to_fun)();
    int i, sum = 0;
    for (i = 1; i <= n; i++) {
    sum += i;
    }
    return sum;
}

int main(int argc, const char *argv[])
{
    ptr_to_fun p;
    p = fun;
    uchar ch = 'a';
    putchar(ch);
    putchar('\n');
    printf("%d\n", (*p)(100));
    return 0;
}

3) 总结:

  • 不管是typedef还是define,都不能在定义之前使用;
  • typedef受函数范围影响,而define不受;

六、宏函数的使用 

1、无参宏 

#define debug printf(“hello world”)
int main() {
debug;
return 0;
}

2、带参宏

1)语法
  • #define 宏名(形参列表) 字符串
  • 不是进行简单的字符串替换,还要进行参数替换
#define debug(s) printf(“%s\n”, s)
int main() {
debug(“helloworld”); //debug(1)保持
return 0;
}
 2)举个栗子
#include<stdio.h>
#define SQUARE(n) (n)*(n)
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d\n", SQUARE(n));
return 0;
}
#define PI 3.1415926
//#define S(r) PI*r*r
//如果传两个参数就会变成,s=3.1415926*a+b*a+b;这样运算的优先级会出问题
//如果要使运算的优先级没有问题则写成下面的这种形式
#define S(r) PI*(r)*(r)
int main(int argc, const char *argv[])
{
float a = 2;
float b = 3;
float s = 0;
s=S(a+b);
printf("sum=%f\n ",s);
return 0;
}

3、宏函数的作用

#define MAX(a,b) ((a) > (b) ? (a) : (b))
  • 和函数不同,宏的参数没有数据类型,因为是文本展开
  • 因为是文本展开,相比函数没有执行调度的开销,效率要高
  • 使用有参的宏函数时,参数再替换文字中要用括号包围,以免受到运算符优先级的影响

4、 函数实现-两个整数相加

#include <stdio.h>

int ADD(int x,int y){
        return x + y;
}
int main(){
        int a = 10;
        int b = 20;
        int sum = ADD(a,b);
        printf("%d\n",sum);
        return 0;
}
#include<stdio.h>
// ADD是宏名,(x,y)是宏的参数但无类型,((x)+(y))是宏体
#define ADD(x,y) ((x)+(y))
int main() {
int a = 10;
int b = 20;
int sum = ADD(a, b);//int sum = ((a)+(b))
//宏是替换的,有替换作用
printf("%d\n", sum);//打印结果:30
return 0;
}

七、#define定义的宏和函数的区别

  • 宏在调用时的效率是比函数高很多的;
  • 函数的参数是有类型的,也存在类型检查。但宏的参数是没有类型与类型检查的;
  • 函数可以递归,而宏不可以递归;
  • 函数方便调试,而宏是不方便调试的;
  • 对于参数而言,宏的参数是直接替换的,所以会有一些参数具有副作用。而函数的参数是临时拷贝的,没有副作用的情况; 
  • 25
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值