带参数的宏和函数很相似,但有本质上的区别:宏展开仅仅是字符串的替换,不会对表达式进行计算;宏在编译之前就被处理掉了,它没有机会参与编译,也不会占用内存。而函数是一段可以重复使用的代码,会被编译,会给它分配内存,每次调用函数,就是执行这块内存中的代码。

【示例①】用函数计算平方值。

  1. #include <stdio.h>
  2. int SQ(int y){
  3. return ((y)*(y));
  4. }
  5. int main(){
  6. int i=1;
  7. while(i<=5){
  8. printf("%d^2 = %d\n", (i-1), SQ(i++));
  9. }
  10. return 0;
  11. }

运行结果:
1^2 = 1
2^2 = 4
3^2 = 9
4^2 = 16
5^2 = 25

【示例②】用宏计算平方值。

  1. #include <stdio.h>
  2. #define SQ(y) ((y)*(y))
  3. int main(){
  4. int i=1;
  5. while(i<=5){
  6. printf("%d^2 = %d\n", i, SQ(i++));
  7. }
  8. return 0;
  9. }

在 Visual Studio 和 C-Free 下的运行结果(其它编译器的运行结果可能不同,这个++运算的顺序有关):
3^2 = 1
5^2 = 9
7^2 = 25

在示例①中,先把实参 i 传递给形参 y,然后再自增 1,这样每循环一次 i 的值增加 1,所以最终要循环 5  次。

在示例②中,宏调用只是简单的字符串替换,SQ(i++) 会被替换为 ((i++)*(i++)),这样每循环一次 i 的值增加 2,所以最终只循环 3  次。

由此可见,宏和函数只是在形式上相似,本质上是完全不同的。

带参数的宏也可以用来定义多个语句,在宏调用时,把这些语句又替换到源程序中,请看下面的例子:

  1. #include <stdio.h>
  2. #define SSSV(s1, s2, s3, v) s1 = length * width; s2 = length * height; s3 = width * height; v = width * length * height;
  3. int main(){
  4. int length = 3, width = 4, height = 5, sa, sb, sc, vv;
  5. SSSV(sa, sb, sc, vv);
  6. printf("sa=%d, sb=%d, sc=%d, vv=%d\n", sa, sb, sc, vv);
  7. return 0;
  8. }

运行结果:
sa=12, sb=15, sc=20, vv=60

C语言:带参数的宏与函数的区别的更多相关文章

  1. C语言带参数的main函数

    C语言带参数的main函数 #include<stdio.h> int main(int argc,char*argv[]) { int i; ;i<argc;i++) printf ...

  2. C语言中带参数的宏

    带参数的宏定义有如下的格式: [#define 指令----带参数的宏] #define 标识符(x1,x2,……,xn) 其中  x1,x2,……xn是标志符(宏的参数) 注意:在宏的名字和括号之间 ...

  3. 编译预处理 -- 带参数的宏定义--【sky原创】

    原文:编译预处理 -- 带参数的宏定义--[sky原创] 如有转载请注明出处   编译预处理  --  带参数的宏定义 前面为输出文件,后面为输入文件 gcc -E -o test.i test.c ...

  4. 宏和函数的区别(一个BUG的总结)

    [1]BUG简单示例代码 主要代码如下: #include <QCoreApplication> #include <QDebug> #define ADD(a, b, c) ...

  5. C语言可变参数在宏定义中的应用

    在C语言的标准库中,printf.scanf.sscanf.sprintf.sscanf这些标准库的输入输出函数,参数都是可变的.在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用 ...

  6. ytu 1057: 输入两个整数,求他们相除的余数(带参的宏 + 模板函数 练习)

    1057: 输入两个整数,求他们相除的余数 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 177  Solved: 136[Submit][Status ...

  7. 【转载】C语言 构建参数个数不固定函数

    深入浅出可变参数函数的使用技巧本文主要介绍可变参数的函数使用,然后分析它的原理,程序员自己如何对它们实现和封装,最后是可能会出现的问题和避免措施. VA函数(variable argument fun ...

  8. 装饰器1、无参数的装饰器 2、有参数的装饰器 3、装饰器本身带参数的以及如果函数带return结果的情况

     装饰器分成三种: 1.无参数的: 2.有参数的: 3.装饰器本身带参数的. 装饰器decorator又叫语法糖 定义:本质是函数,器就是函数的意思.装饰其他函数.就是为其他函数添加附加功能. 原则: ...

  9. 论httpclient上传带参数【commons-httpclient和apache httpclient区别】

    需要做一个httpclient上传,然后啪啪啪网上找资料 1.首先以前系统中用到的了commons-httpclient上传,找了资料后一顿乱改,然后测试 PostMethod filePost = ...

随机推荐

  1. Go语言的函数02---参数

    package main import "fmt" /* 常量,变量,函数---源代码的成员 给成员命名的字符称之为[标识符] 合法的标识符有:大小写字母,数字,下划线 命名时不能 ...

  2. java 常见OPTS参数的含义

    1. -XX:MaxPermSize=256m -XX:MaxPermSize=128M JVM最大允许分配的非堆内存,按需分配 2. java.awt.headless Headless模式是系统的 ...

  3. matrix_multiply代码解析

    matrix_multiply代码解析 关于matrix_multiply 程序执行代码里两个矩阵的乘法,并将相乘结果打印在屏幕上. 示例的主要目的是展现怎么实现一个自定义CPU计算任务. 参考:ht ...

  4. IDEA骚技巧

    1. var 声明 2. null 判空 3. notnull 判非空 4. nn 判非空 5. for 遍历 6. fori 带索引的遍历 7. not 取反 8. if 条件判断 9. cast ...

  5. HashMap源码解析和设计解读

    HashMap源码解析 ​ 想要理解HashMap底层数据的存储形式,底层原理,最好的形式就是读它的源码,但是说实话,源码的注释说明全是英文,英文不是非常好的朋友读起来真的非常吃力,我基本上看了差不多 ...

  6. day20200912

    连杆通过运动副相对于啮合连杆运动 ! 运动副: 旋转副:仅旋转 滑动副:仅沿直线滑动 柱面副:可旋转可沿直线滑动 其他: 可以设置上限.下限 3D接触 驱动: 简谐驱动 函数驱动 运动函数驱动

  7. MySQL的Limit 性能差?真的不能再用了?

    首先说明一下MySQL的版本: mysql> select version();+-----------+| version() |+-----------+| 5.7.17 |+------- ...

  8. 【模拟8.03】斐波那契(fibonacci) (规律题)

    就是找规律,发现每个父亲和孩子的差值都是距儿子最大的fibonacc 也是可证的 f[i]表示当前月的兔子总数 f[i]=f[i-1]+f[i-2](f[i-2]是新生的,f[i-1]是旧有的) 然后 ...

  9. Pytest学习笔记4-assert断言

    前言 pytest作为单元测试框架,自然少不了断言功能,用过unittest的人都知道,在unittest中有丰富的断言方法,比如assertEqual().assertIn().assertTrue ...

  10. npm i安装命令中的-g -D -S的区别

    -g为全局安装 -D 对模块进行局部安装,模块写入到 devDependencies 对象 用于开发阶段,开发时用到的工具等 -S 局部安装,不同的是模块写入到 dependencies对象 用于生产 ...