2文件 宏 结构体

1、文件

#pragma warning(disable: 4996):scanf语法审核比较严格,
文件写入的时候,不需要把\0写入到文件中,因为\0是C语言的规定,文件不认识其
写入是从文件开始进行写入,写入之前,会清空文件内容。
if、else之间无花括号,中间只能有1条语句。f系列的输入输出函数都是作用于所有流的的

#define MYFILE "log.txt"

typedef struct students{
	char name[32];
	char sex[4];
	double math;
	double chinese;
	double english;
}s_t;

int main(){
while (1){
		FILE* fp = fopen(MYFILE, "W"); 
		if (NULL == fp){
			printf("fopen");
			return 1;
		}
				int num = 0;scanf("%d", &num);
		struct students *s = malloc(sizeof(struct students)*num);
			int i = 1;
		while (i <= num){
			printf("student %d name# ", i);
			fscanf(fp, "|%8s ", s[i - 1].name);
		printf("student %d sex# ", i);
			fscanf(fp, "| %4s ", s[i - 1].sex);//不需要&,因为数组名=地址
			printf("student %d math# ", i);
			fscanf(fp, "| %1f ", &(s[i - 1].math));
			printf("student %d chinese# ", i);
			fscanf(fp, "| %1f", &(s[i - 1].chinese));
			printf("student %d english# ", i);
			fscanf(fp, "| %1f| ", &(s[i - 1].english));
			i++;
		}
		i = 1;
while (i <= num){
			printf("|%8s | %4s | %.1f | %.1f| %.1f|\n", 	s[i - 1].name, s[i - 1].sex, s[i - 1].math,	s[i - 1].chinese, s[i - 1].english);
			i++;
		}
		free(s);
		s = NULL;
		fclose(fp);
	}

2、编译 宏

assert本质是一个宏,检测条件如果不满足,直接中止,assert只在debug模式中存在,在release中不存在
宏函数:不做计算,只是替换。宏ifdef:判断:是否被定义;#if:判断:是否为真为假。
宏函数=不是函数,只是1个替换,涉及优先级问题,所以宏函数使用时,多加括号
#define Max(a,b)((a)>(b)?(a):(b))
频繁使用某函数,需要建立栈帧,宏函数可以解决此问题
宏定义不检查参数正确性,会有安全隐患;宏定义的常量更容易理解,使用const常量;

写一个宏,整数的二进制位的奇数位和偶数位交换:

#define EXCHANGE(x)(((x&Ox55555555)<<1 
)|((x&OxAAAAAAAA))//即:奇数位|偶数位
int main(
 int x = 3;//交换前
int y = EXCHANGE(x);//交换后
}
#define SQR(A)A*A
void main( ) {
int x=6 , y=3,z=2;
x/=SQR(y+z)/sQR(y+z);cout< <x< < endl;}
x/=3+2 *3+2 /3+2*3+2=
x/=17=0

预处理只会处理#开头的语句,
编译阶段只校验语法,
汇编:将编译完成之后的汇编指令翻译成对应的二进制格式
链接时才会去找实体,将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,只会链接调用了的函数/全局变量,如果存在一个不存在实体的声明(函数声明、全局变量的外部声明),但没有被调用,依然是可以正常编译执行的。头文件是不参与编译的----因为在预处理阶段已经将头文件展开了,编译是只对源文件进行编译,每个源文件编译完成或都会生成一个obj的目标文件
编译过程中:在其声明中将这个函数名找到了,此时并不知道他的地址,在链接的时候才会真真的去找他的地址,对于C语言来说,每一个函数名就对应一个地址,此时如果出现同名函数那么他就不知道到底这个地址应该填写哪一个了

#define INT_PTR int*
typedef int*int_ptr;//typedef 管 类型
INT_PTR a,b;//等价于“int*a,b;”b只是一个int变量
int_ptr c,d;//c、d都是指针

5.结构体 自定义类型

结构体只能整体初始化,不能整体赋值,结构体传参不发生降维。如果结构体包含了结构体,内部结构体的对齐数是自身的最大对齐数。如果结构体包含了数组,第一个元素对齐了,其他都对齐了元素大小,数组的对齐数=元素大小。对齐的目的:以空间换时间

struct S4{
char c1;
struct S3 s3 ;//大小=16.对齐数=8
double d;
char *p:
short*p[3];//对齐数=4
char x[7];
char *y[3];//对齐数=4
} //结果=72

struct S5{
char a;
double b ;
double*c;
short d[2];//对齐数=2
struct s4 e ;//大小=32.对齐数=8
struct S4*f;
struct s3 g[3];//大小=16.对齐数=8
char h ;
double*i;
struct S2*j[2];
}

在这里插入图片描述
//一个宏,计算结构体中某变量相对首地址的偏移:

struct AA{ 
char a;char b;
double c;} ;
int main (){
printf("%d n"& (((struct AA*)0)->c);}

在一个字节里面,8bit里面,没有大小端;在一个字节里面,不确定哪些比特位属于高比特位(即从左向右还是从右向左存储)c的地扯-c相对于起始的偏移量=起始,结构体变量的地址
枚举本质是整数,占4字节;

联合

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

union Un1
{
 char c[5];//对齐数=1
 int i;//对齐数=4
};
union Un2
{
 short c[7];
 int i;
};
//下面输出的结果是什么?
printf("%d\n", sizeof(union Un1));//8
printf("%d\n", sizeof(union Un2));//16
union//小端
  {    short k;
    char i[2];
  }*s, a;//union只有2字节,2字节的十六进制只有4位
  s = &a;
  s->i[0] = 0x39;
  s->i[1] = 0x38;
  printf(%x\n”,a.k);//3839
typedef struct
{
int a;
short b[2];
}Ex2 ;
typedef struct EX{
int a;
char b[3];
Ex2 c;
struct EX *d;}
Ex ;

在这里插入图片描述
在这里插入图片描述
结构体或者类的自身对齐数:其成员中自身对齐值最大的那个值。
linux:默认对齐数4,vs下默认对齐数: 8
在这里插入图片描述

struct _Record_Struct//结构体内定义的类型=结构体名称=_Record_Struct
{
  unsigned char Env_Alarm_ID : 4;
  unsigned char Para1 : 2;//1
  unsigned char state;//1
  unsigned char avail : 1;//1
}*Env_Alarm_Record;//总结构体=3,*Env_Alarm_Record=以该结构体定义的变量
unsigned char puc[4];
  struct tagPIM
  {
    unsigned char ucPim1;
    unsigned char ucData0 : 1;
    unsigned char ucData1 : 2;
    unsigned char ucData2 : 3;
  }*pstPimData;
  pstPimData = (struct tagPIM*)puc;
  memset(puc,0,4);
  pstPimData->ucPim1 = 2; 
  pstPimData->ucData0 = 3;
  pstPimData->ucData1 = 4;
  pstPimData->ucData2 = 5;
  printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);//02 29 00 00

在这里插入图片描述

位段

在这里插入图片描述
在这里插入图片描述
位段的跨平台问题

  1. int 位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值