C语言-->(十四)结构体、宏、编译
知识点:
1.结构体 struct
2.typedef关键字
3.宏的定义
4.宏与函数的区别
5.文件包含和多文件编译
6.条件编译
===========================
结构体
思考:如果现在希望保存一个学生的信息,姓名,身高,年龄,地址,该如何保存
char name[64];
float height;
int age;
char addr[64];
1.什么是结构体 struct
结构体指的是一种数据结构,是c语言中复合数据类型的一
种多种不同数据类型的集合
2.结构体的作用
结构体可以用来创建复杂的数据结构
3.结构体的定义
1)定义的语法
struct 结构体名
{
成员列表
};
4.结构体成员声明
1)可以声明各种类型的成员
2)成员声明时需要注意的地方
练习:
1.定义一个结构体,用来描述时间,
具体说该结构体有三个成员,分别描述时分秒信息
//1构造一个时间类型
//2把当前时间存到时间变量
//3显示时间变量
2.定义一个结构体,用来描述书本的信息,
结构体成员包括 名称,单价,作者,出版社,出版日期
5.声明结构体类型变量和初始化 //"C programe",38.8,"谭浩强","清华"
(1)方法一
(2)方法二
6.结构体成员的访问方式
结构体变量名.成员名
练习:
1.初始化并输出时间结构体的信息
2.初始化并输出书本结构体的信息
3.从终端输入书本的信息,并且输出
7.结构体数组
数据类型 数组名 数组长度
练习:
1.建立包含2个学生信息的登记表,其中包括学号,姓名,性别,住址和3门成绩 c cpp OC
8.结构体指针 ->
9.结构体的大小和内存对齐
1)思考:为什么会出现相同机构体,大小不同的情况
2)原因:大致可以分为2点
在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。
从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,
但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,
这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐。
内存对齐的原因:
1)某些平台只能在特定的地址处访问特定类型的数据;
2)提高存取数据的速度。比如有的平台每次都是从偶地址处读取数据,对于一个int型的变量,若从偶地址单元处存放,则只需一个读取周期即可读取该变量;但是若从奇地址单元处存放,则需要2个读取周期读取该变量。
3)对齐方式
1>和编译器有关,一般32位系统默认以4个字节方式对齐
2>本系统以结构体中最大元素的类型进行对齐
==========================================================================
typedef关键
思考:程序的跨平台性 64 32 16 8
int int int2
long long long
size_t
long long int64
1.typedef作用
1)typedef常用来定义一个标识符和及关键字的别名,并不分配实际的内存
2)typedef可以增强程序的可读性
3)typedef可以增强标识符的灵活性
2.typedef本质
typedef本质为类型的别名
3.typedef语法使用
typedef 已有类型名 新类型名;
4.重定义结构体
5.重定义类型
6.typedef与define的区别
1)typedef是为了程序的可读性而为标识符另起的别名,而
define在c语言中是为了定义常量,常用代码替换
2)define可以使用#ifdef和#ifndef来进行逻辑判断
==========================================================================
宏定义
0.什么是宏定义
1)宏定义是C提供的三种预处理功能中的一种,预处理包括宏定义、文件包含、条件编译
1.宏定义的作用
1)使用标识符来替换一些常用的代码
WALK 小明---nickname 别名
2.宏定义的本质
1)一种占位符,用来代替一些常用代码
2)一切以转换为前提,做任何事情之前先要替换
2.基本的宏定义
0)#define指令语法
宏指令 宏名 宏体
1)标识符
2)大写,不加分号结束
3)使用
示例:定义常量PI的宏
练习:
定义数组大小的宏
定义重力加速度宏 9.8
3.带有参数的宏定义
1)示例:计算两数最大值的宏
练习:
1.计算两数之和的宏,两数之积
思考:ADD(1,2)*ADD(1,2)结果
4.宏替换的问题
1)宏替换作用的演示,gcc编译参数
2)思考:能否嵌套定义或调用
5.宏和函数的区别
1 )宏会在编译器在对源代码进行编译的时候进行简单替换,不会进行任何逻辑检测,即简单代码复制而已。
2)宏进行定义时不会考虑参数的类型。
3)参数宏的使用会使具有同一作用的代码块在目标文件中存在多个副本,即会增长目标文件的大小。
4)参数宏的运行速度会比函数快,因为不需要参数压栈/出栈操作。
5)参数宏在定义时要多加小心,多加括号。
6)函数只在目标文件中存在一处,比较节省程序空间。
7)函数的调用会牵扯到参数的传递,压栈/出栈操作,速度相对较慢。
8)函数的参数存在传值和传地址(指针)的问题,参数宏不存在。
==================================
文件包含和多文件编译
1.思考:如何实现多人合作项目
接口---->函数原型 .h //head
实现---->函数定义 .c
cvs git svn
2.回忆函数定义和声明
3.头文件和源文件
4.#include指令语法!!!!
1)本质:头文件包含实际是替换文件内容
2)作用:实现声明和实现相分离,进一步使程序更加的模块化
#include <stdio.h> 尖括号表示系统标准目录
双引号表示自定义路径
add, sub, mut, div + -
5.示例:链表的实现的声明相分离
练习:
1.实现加减乘除四则运算,并将函数的声明与实现相分离
并编写测试函数测试该些函数
A B C D 200 100
==========================================================================
条件预编译
需求:现在用户只购买系统中的某些模块
1.思考:如何可以简单快速的在编译的过程中满足用户的需求
2.#ifdef 条件编译语法
#ifdef 标示符
程序段1
#else
程序段2
#endif
#ifndef
1)作用:模块选择
示例:判断是否定义过PI宏
练习:判断是否有定义上述的常用宏
思考:
1.如何可以安全,快速的注释代码
2.// 和 /* */注释是否可以嵌套使用
3.#if 条件编译语法
#if 表达式
程序段1
#else
程序段2
#endif
1)作用
快速安全的注释代码
4.安全注释
思考:如果重复包含头文件会如何
5.防止头文件重复包含
#ifndef TEST_H_H头文件名
#define TEST_H_H
#include "test.h"
#endif
==========================================================================
调试宏
思考:如何使用printf调试代码,是否方便移出
1.调试宏定义
INFO, WARN, ERROR, DEBUG
2.调试开关
3.预定义宏
printf("line = %d, file = %s, DATA = %s, TIME = %s",
__LINE__, __FILE__, __DATE__, __TIME__);
__LINE__:行号
__FILE__:文件名
__DATE__:日期 %s
__TIME__:时间
__func__:函数名
==========================================================================