Linux C语言:#define和typedef

一、预处理指令#define

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

二、没有值的宏定义

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

1、#define 名字

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

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

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

2、#include预处理指令

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

三、宏定义和 const 常量区别

1、 定义的区别

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

2 、处理阶段阶段的不同

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

3 、存储方式不同

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

4 、是否进行类型检查

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

5 、宏定义可以声明函数

6、定义后能否取消

  • 宏定义可以通过#undef来使之前的宏定义失效

  • const常量定义后将在定义域内永久有效

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

3、进阶typedef

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

举个栗子:

cs 复制代码
#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)函数指针
cs 复制代码
int (*fun)(int);
使用Typedef:
typedef int (*PTR_TO_FUN)(int);

举个栗子:

cs 复制代码
#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的比较

cs 复制代码
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声明后的引用都是正确的

  • 不管是在某个函数内,还是在所有函数之外,作用域都是从定义开始直到整个文件结尾。
cs 复制代码
#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;
}
  1. 总结:
  • 不管是typedef还是define,都不能在定义之前使用;
  • typedef受函数范围影响,而define不受;

六、宏函数的使用

1、无参宏

cs 复制代码
#define debug printf("hello world")
int main() {
debug;
return 0;
}

2、带参宏

1)语法
  • #define 宏名(形参列表) 字符串
  • 不是进行简单的字符串替换,还要进行参数替换
cs 复制代码
#define debug(s) printf("%s\n", s)
int main() {
debug("helloworld"); //debug(1)保持
return 0;
}
2)举个栗子
cs 复制代码
#include<stdio.h>
#define SQUARE(n) (n)*(n)
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d\n", SQUARE(n));
return 0;
}
cs 复制代码
#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、宏函数的作用

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

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

cs 复制代码
#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;
}
cs 复制代码
#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定义的宏和函数的区别

  • 宏在调用时的效率是比函数高很多的;
  • 函数的参数是有类型的,也存在类型检查。但宏的参数是没有类型与类型检查的;
  • 函数可以递归,而宏不可以递归;
  • 函数方便调试,而宏是不方便调试的;
  • 对于参数而言,宏的参数是直接替换的,所以会有一些参数具有副作用。而函数的参数是临时拷贝的,没有副作用的情况;
相关推荐
一只特立独行的猪6111 小时前
Java面试——集合篇
java·开发语言·面试
只对您心动1 小时前
【C高级】有关shell脚本的一些练习
linux·c语言·shell·脚本
大得3692 小时前
go注册中心Eureka,注册到线上和线下,都可以访问
开发语言·eureka·golang
小珑也要变强3 小时前
队列基础概念
c语言·开发语言·数据结构·物联网
AI原吾5 小时前
掌握Python-uinput:打造你的输入设备控制大师
开发语言·python·apython-uinput
机器视觉知识推荐、就业指导5 小时前
Qt/C++事件过滤器与控件响应重写的使用、场景的不同
开发语言·数据库·c++·qt
毕设木哥5 小时前
25届计算机专业毕设选题推荐-基于python的二手电子设备交易平台【源码+文档+讲解】
开发语言·python·计算机·django·毕业设计·课程设计·毕设
珞瑜·5 小时前
Matlab R2024B软件安装教程
开发语言·matlab
weixin_455446175 小时前
Python学习的主要知识框架
开发语言·python·学习
孤寂大仙v5 小时前
【C++】STL----list常见用法
开发语言·c++·list