概念

以“#”号开头的都是预处理命令

例如 #include <stdio.h>宏定义

宏定义
无参数的宏名后不带参数
# 表示这是一条预处理命令, define 为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数,表达式、格式串等

举例:

#define PI 3.1415926

作用:

就是用指定标识符PI来代替数3.1415926
对源程序作编译时, 将先由预处理程序进行宏代换,
即用3.1415926表达式去置换所有的宏名PI, 然后编译

#include <stdio.h>

# define PI 3.1415

int main(int argc, char const *argv[]) {
printf("%f\n", PI);
return ;
}

注意:

1. 预处理程序对宏定义不做任何检查,如果有错误,只能在编译已被宏展开后的源程序是发现

2. 宏定义不是说明或语句,在行末不必加分好,如加上分好则连分号也一起置换 容易出错的地方

3. 宏定义必须写在函数之外, 其作用域为宏定义命令起到源程序结束。如要终止其作用域可
使用# undef命令

4. 宏定义用双引号括起来的都是常量字符串 例如“PI” 则打印PI

5. 宏定义允许嵌套, 在宏定义的字符串中,可以使用已定义的宏名。在宏展开时由预处理程序层层代换。

6. 习惯上宏定义用大写字母表示, 以便区分

      #include <stdio.h>

      # define PI 3.1415
# define S PI*r*r int main(int argc, char const *argv[]) {
double s;
int r;
scanf("%d", &r);
s = S;
printf("%d\n", s);
return ;
}

7. 可用宏定义表示数据类型, 是书写方便

# define INTEGER int 

8. 对“输出格式”作宏定义, 可以缩减书写麻烦

#include <stdio.h>

# define P printf
# define D "%d\n" int main(int argc, char const *argv[])
{
p(D, ); }

define 和typeof的区别

宏定义      只是简单的字符串代换, 是预处理完成的。
typedef    是在编译时处理的, 它不是作简单的代换, 而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。
typedef    相当于类型重命名

#include <stdio.h>

#define  PIN1 char*  // -->通常我们用define定义数值
typedef char* PIN2; // -->通常我们用typedef定义数据类型和结构 int main(int argc, char const *argv[]) { PIN1 x, y; // char* x, y;也就是 char *x, y
PIN2 a, b; // char* a, b; char *a, *b;
printf("%d %d\n", sizeof(x), sizeof(y));
printf("%d %d\n", sizeof(a), sizeof(b));
//结果:
// 8 1
//8 8
}

带参数宏定义

c语言允许宏带有参数, 在宏定义中的参数成为形式参数, 在宏调用中的参数成为实际参数。

对带参数的红,在调用中, 不仅要展开,而且要用实参去代替形参

带参宏定义的一般形式为:

# define 宏名(形参表) 字符串
带参宏调用的一般形式为: 宏名(实参表)

例如:

	#define M(y) y*y+3*y /*宏定义*/

	。。
k=M(5); /*宏调用*/
相当于k = 5*5 + 3*5 会直接替换,没有预处理的过程

  

看例子

#include <stdio.h>

#define MAX(a, b) (a, b)?a:b

int main(int argc, char const *argv[])
{
int x, y, max; scanf("%d %d", &x, &y);
max = MAX(x, y);
printf("%d\n", max);
return ;
}

注意:

首先win编程里面都是宏定义

1. 带参宏定义中,宏名和形参表之间不能有空格出现
例如:

正确:
#define MAX(a, b) (a>b)?a:b
错误:
#define MAX (a, b) (a>b)?a:b

2. 在带参宏定义中,形式参数不分配内存单元, 因此不必作类型定义。
而宏调用中的实参有具体的值。要用他们去代换形参, 因此必须作类型说明

3. 在宏定义中的形参是标识符, 而宏调用中的实参可以是表达式

4. 在宏定义中, 字符串内的形参通常要用括号括起来以避免出错。
例如 # define M(y) (y)^(y)表达式的y都用括号括起来, 因此结果是正确的。
如果去掉括号, 把程序改成一下形式,那么程序的结果不是你想要的结果

注意:

#define S(y) (y)*(y)

.....
sq = / S() //等于160 / (y)*(y)
需要更改成 #define S(y) ((y)*(y))

5. 带参宏和带参函数很相似, 但有本质上的不同, 除上面已谈到的各点外,
把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。

稍等例子,明天测试

6. 宏定义也可以定义多个语句, 在宏调用时, 把这些语句又代换到源程序内
#include <string.h>
# define S(s1, s2) strcat(s1, s2) //strcat 类似连接,或合并

宏定义的if

条件编译三种形式:
1. #ifdef 标识符
    程序段1
  #else
    程序段2
  #endif

2. #ifndef 标识符
    程序段1
  #else
    程序段2
  #endif

3.#if 常量表达式
    程序段1
  #else
    程序段2
  #endif

c 预处理的宏定义的更多相关文章

  1. define预处理以及宏定义

    define的定义方式 无参一般形式:#define 标认符 字符串                     比如:#define COUTD "%d\n" 带参一般形式:#def ...

  2. 标C编程笔记day04 预处理、宏定义、条件编译、makefile、结构体使用

    预处理:也就是包括须要的头文件,用#include<标准头文件>或#include "自己定义的头文件" 宏定义,如:#define PI 3.1415926 查看用宏 ...

  3. C预处理之宏定义

    #include <stdio.h> //定义不带参数的宏 #define PI 3.14 /*********************************************** ...

  4. C++面试常见问题——01预处理与宏定义

    C++面试常见问题--------01预编译和宏的使用 C++预处理器 预处理器是一些指令,它将指示编译器在实际编译之前需要完成的预处理.预处理必须要在对程序进行词法与语义分析.代码生成与优化等通常的 ...

  5. C语言预处理理论-宏定义2

    宏定义21.带参宏和带参函数的区别(1)宏定义是在预处理期间处理的,而函数是在编译期间处理的.这个区别带来的实质差异是:宏定义最终是在调用宏的地方把宏体原地展开,而函数是在调用函数处跳转到函数中去执行 ...

  6. C语言预处理理论-宏定义1

    宏定义1宏定义的规则和使用解析(1)宏定义的解析规则就是:在预处理阶段由预处理器进行替换,这个替换是原封不动的替换.(2)宏定义替换会递归进行,直到替换出来的值本身不再是一个宏为止.#define M ...

  7. 【C语言】预处理、宏定义、内联函数 _

    一.由源码到可执行程序的过程 1. 预处理: 源码经过预处理器的预处理变成预处理过的.i中间文件   1 gcc -E test.c -o test.i 2. 编译: 中间文件经过编译器编译形成.s的 ...

  8. 【C语言】预处理、宏定义、内联函数

    一.由源码到可执行程序的过程 1. 预处理: 源码经过预处理器的预处理变成预处理过的.i中间文件 1 gcc -E test.c -o test.i 2. 编译: 中间文件经过编译器编译形成.s的汇编 ...

  9. 09.C语言:预处理(宏定义)、字节序、地址对齐

    一.预处理 预处理 gcc -E Hello.c -o hello.i 编译 gcc -S hello.i -o hello.s 汇编 gcc -c hello.s -o hello.o 链接 gcc ...

随机推荐

  1. android 覆盖安装问题

    1.android中覆盖安装不会导致data/data/package下的数据被删除 2.数据库会有数据库的一套升级机制 3.sharepreference 不会被覆盖,如果在app中有使用Key记录 ...

  2. 每日英语:The Toy Mogul Who Became A Billionaire Through His Fight To The Death With Barbie

    The trophy case in the tiny conference room outside Isaac Larian’s corner office spans an entire wal ...

  3. python(59):yield 函数

    可迭代对象: 当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象: >>> mylist = [1, 2, 3] >>> for i in myli ...

  4. 通过kafka提供的命令来查看offset消费情况

    使用kafka的bin目录下面的kafka-consumer-groups.sh命令可以查看offset消费情况,注意,如果你的offset是存在kafka集群上的,就指定kafka服务器的地址boo ...

  5. 关于electron的跨域问题,有本地的图片的地址,访问不了本地的图片

    项目中有上传图片功能,自定义input type=file 改变透明度和超出部分隐藏,把按钮和 点击的图标放在上传文件的按钮上面,然后又碰到到获取input里面的图片的本地的路径, 在electron ...

  6. 搜索页面scroll下拉时候进行刷新,显示更多搜索值

    1.封装扩展scroll.vue功能: //props传值 pullup:{ type:Boolean, default:false } _initScroll(){ if(!this.$refs.w ...

  7. poj1077(康托展开+bfs+记忆路径)

    题意:就是说,给出一个三行三列的数组,其中元素为1--8和x,例如: 1 2 3 现在,需要你把它变成:1 2 3 要的最少步数的移动方案.可以右移r,左移l,上移u,下移dx 4 6 4 5 67 ...

  8. Orcale分析函数OVER(PARTITION BY... ORDER BY...)的讲解

    顾名思义,PARTITION 中文是分割的意思,ORDER 是排序的意思,所以翻译一下就是先把一组数据按照制定的字段进行分割成各种组,然后组内按照某个字段排序. 以实际案例来说明这个函数的使用, 首先 ...

  9. C#学习笔记(4)——sqlserver常用语句

    说明(2017-5-26 17:29:05): 需要天天练习: 新建表:create table [表名]([自动编号字段] int IDENTITY (1,1) PRIMARY KEY ,[字段1] ...

  10. golang前后端jwt对接

    0x0 什么是jwt JWT是JSON Web Token的缩写,可以用作授权认证.传统的授权认证一般采用session,由于session存储在服务端,加大了服务端的计算量, 而且多台服务器之间存在 ...