C语言:高级议题

高级议题

1、预处理

预处理指的是编译器在编译程序之前对源程序处理的过程

<1>去掉程序中的注释

/*
多行注释
*/
//单行注释

<2>头文件包含

//预处理命令:#include
//头文件包含指的是将头文件中的内容拷贝到当前的源文件中
①包含系统头文件
#include<头文件名称.h> //直接去系统头文件目录中找头文件
②包含自己写的头文件
#include"头文件名称.h" //现在当前目录中找,如果找不到再去系统目录中找

<3>宏替换

//将源文件中所有的宏的符号用后面的字符串替换
//宏指的是用#define定义的符号
①预定义宏——系统已经定义好的宏,直接在程序中可以使用
FILE 正在编译的源文件的名称
LINE 文件当前的行号
FUNCTION 当前所在的函数名
DATE 预编译文件的日期
TIME 预编译文件的时间
STDC 判断编译器是否遵循ANSI C,是则为1
其中,_LINE_和_STDC_是整型常量,其余为字符串常量。
例如:

#include <stdio.h>

int main(void)
{
	printf("%s\n",__FILE__);
	printf("%d\n",__LINE__);
	printf("%s\n",__FUNCTION__);
	printf("%s\n",__DATE__);
	printf("%s\n",__TIME__);
	printf("%d\n",__STDC__);
	return 0;
}

②不带参数的宏
例如:

#define PI 3.14
#define MIN  60

③带参数的宏
例如:

#define MAX(a,b) a>b?a:b
		
//带参宏可以在程序中被调用,例如 
MAX(3,5) = 5 
MAX(3.4,2.1) = 3.4 
MAX("hello","world") = "world"
			
#define ADD(a,b)  a*b+a
ADD(3+4,2+5) --> 3+4 * 2+5 +3+4 = 23  //这个结果和想要的结果不一致,所以在定义带参宏时,需要给参数加(),保证结果一致
			
#define ADD(a,b)  (a)*(b)+(a)
ADD(3+4,2+5) --->(3+4) * (2+5) + 3+4 = 56

<4>条件编译

根据条件选择性的编译程序中的某一部分代码
①第一种形式
#ifndef 宏 //如果定义了宏,则编译代码段A,否则,编译代码段B
代码段A
#else
代码段B
#endif
//用于测试代码中
//#define DEBUG

#include <stdio.h>

float my_power(float a, int n)
{
	float b = 1.0;
	int i;

	if(n == 0)
		return b;
	else if(n > 0){ 
		for(i = 0; i < n; i++)
			b *= a;
		return b;
	}else{
		for(i = 0; i < -n;i++)
			b *= a;
		return 1/b;
	}   
}
#ifdef DEBUG			//通过定义这个宏,控制下面的测试代码是否被编译
int main(void)
{
	float a;
	int n;

	printf("请输入浮点数和指数:");
	scanf("%f%d",&a,&n);

	printf("%f\n",my_power(a,n));
}
#endif

②第二种形式
#ifndef 宏//如没有定义宏,则编译代码段A,否则,编译代码段B
代码段A
#else
代码段B
#endif
//用于头文件中——作用:防止头文件被重复包含
③第三种形式
#if 表达式 //如表达式为真,则编译代码段A,否则,编译代码段B
代码段A
#else
代码段B
#endif
//用于注释中
例如:

int main(void)
{
#if 0
	printf("hello world\n");
#else
	printf("farsight\n");
#endif

	return 0;
}

2、字节序

<1>概念

字节序指的是处理器在对字(大于一个字节的数据)取值时,解释其中各个字节的顺序

<2>大端序和小端序

大端序:低字节数据保存在高地址位置,其他字节数据依次保存在低地址位置,这种字节序称为大端序
小端序:低字节数据保存在低地址位置,其他字节数据依次保存在高地址位置,这种字节序称为小端序

<3>如何判断当前的机器属于哪种字节

nt main(void)
{
	unsigned int a = 0x12345678;
	unsigned char b;
	b = *(unsigned char*)&a;
	if(b == 0x78)
		printf("小端序\n");
	else
		printf("大端序\n");
	return 0;
		}		

3、地址对齐

<1>概念

为了提高机器访问内存中的数据的效率,给数据在内存中分配空间时,将数据的空间分配在某些特殊的地址位置
这种分配空间的方式称为地址对齐

地址对齐分为自然对齐和适当对其

<2>自然对齐

如果某个数据的地址能够被它的长度整除,则这种分配内存的方式称为自然对齐。

<3>适当对齐

数据的M值——每一个数据都存在一个M值
如果数据的长度<机器字长,M值取数据的长度
如果数据的长度>=机器字长,M取机器字长

适当对齐:如果某个数据的地址能够被它的M值整除,则这种分配内存的方式称为适当对齐

<4>C语言中的数据对齐——32bit机器

基本类型数据——按数据的M值对齐
例如:
–|--
char|1个字节对齐
short|2个字节对齐
int|4个字节对齐
float|4个字节对齐
double|4个字节对齐

数组——按数组元素的M值对齐

联合体和结构体——成员中最大的M值对齐
联合体,举例:

union A{
	short a;		M值:2
	float b;		M值:4
	double d;		M值:4
}; 			//按4个字节对齐

结构体,举例:

#include <stdio.h>
#include <string.h>

#pragma pack(push)    //将默认对齐方式压栈
//指定1个字节对齐
#pragma pack(1)
struct A{
	char a;
	int b;
	short c;
};
#pragma pack(pop)   //还原默认的对齐方式
struct B{
	char a;
	short c;
	int b;
};
int main(void)
{
	struct A st1;
	struct B st2;

	printf("sizeof(st1) = %d\n",sizeof(st1));
	printf("sizeof(st2) = %d\n",sizeof(st2));
	return 0;
}

4、特殊函数

<1>递归函数

如果一个函数中,调用了自身,则这样的函数称为递归函数,例如:

void fun(void )
{
	printf("hello world\n");
	fun();
}

一个正确的递归函数,必须具备以下几个条件:
递推阶段,回归阶段,地推终止条件

所以,上面的递归函数可以修改为:

void fun(int n)
{
	printf("hello world\n");
	if(n > 0)  //递推终止条件
		fun(n-1);
}

int main(void)
{
	fun(5);
	return 0;
}

<2>变参函数

调用函数时,如果可以传递不同类型或者不同个数的参数,这样的函数称为变参函数
变参函数的函数头中,变参用…表示,例如:

int fun(int n,...)
{			
}

//最典型的变参函数就是:printf

int printf(const char *format, ...);

<3>回调函数

把简介调用的函数称为回调函数,例如:

void fun(void)  //回调函数
{
	printf("hello world\n");
}

void fun1(void(*p)(void))
{
	p();  //在fun1中间接调用fun,此时fun就是回调函数
}

int main(void)
{
void fun1(fun);
	return 0;
		}	

<4>内联函数

定义函数时,在返回值类型的前面如果加一个关键字:inline,此时该函数称为内联函数。
把一个函数定义为内联函数,就是要求系统尽可能快的调用该内联函数
此时,内联函数的调用过程就会与普通函数的调用过程不同,它就会以带参宏的调用过程被系统调用

内联函数原则:
①函数体中的代码不易过多
②函数体中不能洗循环语句
③一般为系统中比较重要的代码,希望它能够快速的执行
④内联函数一般会定义在头文件中

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sashimi69

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值