枚举,联合,宏定义,结构体

一,枚举

(1)枚举也可以用来创建新的数据类型,枚举类型存储区就是一个整数类型存储区,只不过这个存储区里只能记录有限的几个整数(2)声明枚举类型时需要提供一组名称,每个名称代表一个整数,这些整数都可以记录在枚举类型存储区里(3)声明枚举类型的时候需要使用enum关键字,第一个枚举名称对应的整数是0,向后依次递增。(4)可以在声明枚举类型的时候指定某个名称对应的整数,它后面的名称对应的整数会随之改变。

enum birth {zhangsan=1998, lisi= 1991, wangwu=1994, chenliu=1993};

二,联合

联合也可以用来声明新的数据类型,联合存储区可以用不同的方式解释。联合也需要声明,声明联合的时候需要使用union关键字。联合存储区的大小是最大使用方式的大小。

#include <stdio.h>
union un 
{
	char buf[2];
	int num;
	float fnum;
};
int main() 
{
	union un abc = {0};
	abc.fnum = 1.0f;
	printf("1.0是0x%x\n", abc.num);
	printf("sizeof(abc)是%d\n", sizeof(abc));
	return 0;
}

三,宏:#define预处理指令可以用来定义宏

1,宏可以用来给数字起名字;定义宏的时候要把宏名称写在前面,把它所代表的数字写在后面;宏名称通常全部由大写英文字母构成;宏名称里不能包含空格;用宏给数字起名字的时候宏定义语句里不能有赋值操作符;编译器会把程序中所有宏名称替换成它所代表的数字;


#define DDR_WRITE8(addr,value) 		*((volatile UINT8 *) (addr)) = value
#define DDR_READ8(addr)				(*(volatile UINT8 *) (addr))
#define DDR_WRITE16(addr,value) 	*((volatile UINT16 *)(addr)) = value
#define DDR_READ16(addr)			(*(volatile UINT16 *)(addr))
#define DDR_WRITE32(addr,value) 	*((volatile UINT32 *)(addr)) = value
#define DDR_READ32(addr)			(*(volatile UINT32 *)(addr))
#define DDR_WRITE64(addr,value) 	*((volatile UINT64 *)(addr)) = value
#define DDR_READ64(addr)			(*(volatile UINT64 *)(addr))

2,可以在编译命令中使用-D选项指定宏所代表的数字。如果程序中的某些数字只能在编译的时候才能确定就应该用宏代表它们;宏还可以用来给计算公式起名字;计算公式里包含未知数字,可以使用宏参数表示这些未知数字;宏的参数不一定代表数字,所以它没有类型名称;如果宏有多个参数,不同参数之间需要用逗号分开

3,编译器采用二次替换的方式处理带参数的宏。宏不能使用自己的存储区和函数进行数据传递。宏没有形式参数也没有返回值。能当作数字使用的宏必须编写成一个表达式(因为宏没有返回值存储区)。宏的参数可以直接代表函数的存储区,因为宏没有返回值存储区,所以不能保证优先计算宏内部的操作符。所有能当作数字使用的宏必须写在一对小括号里。因为宏没有形式参数,所以不能保证优先计算参数内部的操作符。宏的所有能当数字使用的参数也应该写在小括号里。不要把自增或自减的计算结果作为宏的参数。

4,#是一个宏操作符,它可以把宏的参数转换为字符串字面值。##也是一个宏操作符,它可以把一个代表标识符的宏参数和其他内容连接成为一个新的标识符

5,条件编译可以在编译的时候从几组语句中选择一组编译而忽略其他组

(1)#ifdef/#ifndef...#else...#endif:以上结构可以根据一个宏是否被定义过从两组语句中选择一组编译。这个结构最开始的预处理指令是二选一的,这个最开始的预处理指令后要跟着一个宏名称。如果采用#ifdef则它后面的宏名称,如果被定义过就编译前一组,否则编译后一组,如果采用#ifndef则刚好相反

(2)#if...#elif(任意次数)...#else...#endif  以上结构也可以实现条件编译,它可以根据任意逻辑表达式的结果从几组语句中选择一组编译

6,多文件编程时一个文件里可以包含多个函数,一个函数必须完整的属于一个文件

多文件编程基本步骤:

(1).把所有函数分散在多个源文件里(主函数单独占一个文件)

(2).为每个源文件编写配对的头文件(主函数所在源文件不需要配对头文件)所有不分配内存的内容都可以写在头文件里。至少要包含源文件里所有函数的声明

(3).修改所有源文件,让它们包含必要的头文件(配对头文件是必要头文件,如果源文件里使用了某个头文件中声明的函数则这个头文件也是必要头文件)

编译多文件程序时可以在gcc命令中把所有源文件名称列出,也可以把编译过程记录在Makefile里,然后使用make工具进行编译,应该把头文件的内容包含在预处理中,这样可以避免多次编译。

7,最开始的预处理指令必须是#ifndef,头文件里使用的宏名称应该根据文件路径变化得到。

8,如果一个源文件里希望使用另外一个源文件里声明的全局变量就需要使用extern关键字再次声明这个全局变量。使用extern关键字声明变量的语句通常放在头文件里。静态全局变量不可以被其他源文件里的语句使用。

#include<stdio.h>
typedef struct
{
  int x;
  int y;
}point;

point* mid_point(point *a,point *b,point *mid)
{
   mid->x=(a->x+b->x)/2;
   mid->y=(a->y+b->y)/2;
   return mid;
}
int main()
{
   point A,B,C;
   printf("请输入第一个点的坐标(x1,y1)\n");
   scanf("%d,%d",&(A.x),&(A.y));
   printf("请输入第二个点的坐标(x2,y2)\n");
   scanf("%d,%d",&(B.x),&(B.y));
   point *mid_ptr;
   mid_ptr=mid_point(&A,&B,&C);
   printf("这条直线中点的坐标是(%d,%d)\n",C.x,C.y);
   printf("指针读取函数返回值的地址,里面对应的坐标值是:(%d,%d)\n",mid_ptr->x,mid_ptr->y);
}

四,结构体

1,定义:C语言里可以在一个存储区里记录多个相关数字,这种存储区的类型叫结构体类型,这种类型需要程序员编写语句创建出来。

2,结构体存储区里包含多个子存储区,每个子存储区可以用来记录一个数字。

结构体中不同子存储区的类型可以不同,甚至某些子存储区还可以是结构体存储区。

结构体声明语句可以用来创建结构体类型,结构体声明语句中需要使用struct关键字。

结构体声明语句中包含的变量声明语句不会分配内存,它们只是用来表示结构体存储区内部的多个子存储区类型。结构体声明语句可以写在头文件里,结构体类型可以用来声明结构体变量,结构体变量分配了内存,它们可以用来记录数字。

声明结构体变量时需要把struct关键字和结构体类型名称合起来作为类型名称使用。

3,typedef关键字可以用来给现有数据类型起别名别名可以用来替换原有类型名称。

可以把结构体声明语句和起别名语句合并这个时候可以省略结构体本身的名称。

4,C语言不可以在结构体里包含函数结构体变量在声明的时候也应该初始化。

初始化结构体变量的时候可以为每个子存储区提供一个初始化数据,所有初始化数据写在大括号中间,不同数据之间用逗号分开。

5,结构体变量通常不会作为整体使用,一次只会使用其中某个子存储区。可以在结构体变量名称后加.然后再加某个子存储区名称的方法表示某个子存储区。

6,同类型结构体变量之间可以直接赋值,结构体指针用来记录结构体存储区的地址。当结构体指针和结构体存储区捆绑后可以在结构体指针后加->再加上子存储区名称来表示某个子存储区。

7,结构体存储区可以作为形式参数使用但是这样会造成时间和空间的浪费,一般不这么做,使用结构体指针作为形式参数可以避免这种浪费。结构体指针形式参数要尽量加const关键字。

8,不要使用结构体存储区记录返回值,而应该使用结构体指针存储区,这样可以避免时间和空间的浪费,不可以把局部结构体存储区的地址作为返回值使用。

9,一个存储区的地址必须是它自身大小的整数倍(double类型存储区的大小只需要是4的整数倍),这个规则叫做数据对齐,结构体内部的子存储区通常也需要遵守数据对齐的规则,数据对齐可能导致结构体内部不同子存储区之间有空隙。

10,结构体存储区的大小必须是其中占地最大基本类型存储区大小的整数倍(如果占地最大的基本类型存储区是double则结构体存储区的大小只需要是4的整数倍就可以了)这个规则叫做数据补齐。数据补齐可能在结构体存储区最后造成一些浪费的字节。

#include<stdio.h>
typedef struct
{
   char name[14];
   float height;
   int age;
}student;
int main()
{
   student prn;
   printf("请输入学生姓名:\n");
   scanf("%s",&(prn.name));
  printf("请输入学生体重:\n");
  scanf("%g",&(prn.height));
  printf("请输入学生年龄:\n");
  scanf("%d",&(prn.age));
  printf("这个学生姓名是:%s,身高是%gkg,年龄是%d岁\n",prn.name,prn.height,prn.age);
   student person;
   person=prn;
   printf("这个学生姓名是:%s,身高是%gkg,年龄是%d岁\n",person.name,person.height,person.age);
  

  student stu={"wangfang",50.5,28};
printf("这个学生姓名是:%s,身高是%gkg,年龄是%d岁\n",stu.name,stu.height,stu.age);

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

寒听雪落

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

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

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

打赏作者

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

抵扣说明:

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

余额充值