uart 之 可变参数
①.对齐方式结构体
__attribute__ ((packed)); //取消对齐, 结构体占用 13个字节
__attribute((aligned (4))); // 自己指定对齐方式, 4字节, 默认也是 ,结构体16个字节占用
/** struct_test.c V1.0 * Copyright (c) 2017 Shenzhen 100ask Technology Co.Ltd.All rights reserved.* http://www.100ask.org* 100ask.taobao.com** 测试平台: ubuntu16.04(64位机器) gcc -m32 -o struct_test struct_test.c * ubuntu9.10 (32位机器) gcc -o struct_test struct_test.c * 编译器 : gcc*/#include <stdio.h>
/*
由于在x86(32位机器)平台下,GCC编译器默认按4字节对齐,
如:结构体4字节对齐,即结构体成员变量所在的内存地址是4的整数倍。可以通过使用gcc中的__attribute__选项来设置指定的对齐大小。1):
__attribute__ ((packed)),让所作用的结构体取消在编译过程中的优化对齐,
按照实际占用字节数进行对齐。2):
__attribute((aligned (n))),让所作用的结构体成员对齐在n字节边界上。如果结构体中有成员变量的字节长度大于n,则按照最大成员变量的字节长度来对齐。*/
struct person{char *name;int age;char score;int id;
}; //struct person1{char *name;int age;char score;int id;
}__attribute__ ((packed));struct person2{char *name;int age;char score;int id;
}__attribute((aligned (4)));int main(int argc,char **argv)
{struct person per={"www.100ask.org",10,'A',123};printf("sizeof(char )=%d\n",sizeof(char ));printf("sizeof(int )=%d\n",sizeof(int ));printf("sizeof(char *)=%d\n",sizeof(char *));printf("sizeof(char **)=%d\n",sizeof(char **)); printf("sizeof(struct person)=%d\n",sizeof(struct person)); // 结构体16个字节printf("sizeof(struct person1)=%d\n",sizeof(struct person1)); // 结构体13个字节printf("sizeof(struct person2)=%d\n",sizeof(struct person2)); // 结构体16个字节printf("&per.name =%p,per.name =%s\n",&per.name ,per.name);printf("&per.age =%p,per.age =%d\n",&per.age ,per.age); printf("&per.score =%p,per.score =%d\n",&per.score,per.score); printf("&per.id =%p,per.id =%d\n",&per.id ,per.id); return 0;
}
②。 第一种访问可变参数方式,使用连续地址的方式
可变参数入栈,栈内部结构:
编写代码:
/** push_test.c V1.0 * Copyright (c) 2017 Shenzhen 100ask Technology Co.Ltd.All rights reserved.* http://www.100ask.org* 100ask.taobao.com** 测试平台: ubuntu16.04(64位机器) gcc -m32 -o push_test push_test.c * ubuntu9.10 (32位机器) gcc -o push_test push_test.c * 编译器 : gcc*/#include <stdio.h>struct person{char *name;int age;char score;int id;
};
/* *int printf(const char *format, ...); *依据:x86平台,函数调用时参数传递是使用堆栈来实现的 *目的:将所有传入的参数全部打印出来 */
int push_test(const char *format, ...)
{char *p = (char *)&format;int i;struct person per; char c;double d;printf("arg1 : %s\n",format); //==============p = p + sizeof(char *);/*指针对连续空间操作时: 1) 取值 2)移动指针*/ i = *((int *)p);p = p + sizeof(int); printf("arg2 : %d\n",i); //============== /*指针对连续空间操作时: 1) 取值 2)移动指针*/ per = *((struct person *)p); p = p + sizeof(struct person); printf("arg3: .name = %s, .age = %d, .socre=%c .id=%d\n",\per.name, per.age, per.score, per.id); //============== /*指针对连续空间操作时: 1) 取值 2)移动指针*/c = *((char *)p);p = p + ((sizeof(char) + 3) & ~3); printf("arg4: %c\n",c);
// 注意,这里必须移动4个字节, 32位系统4个字节对齐,空出来3个就空了//============== /*指针对连续空间操作时: 1) 取值 2)移动指针*/d = *((double *)p);p = p + sizeof(double);printf("arg5: %f\n",d);return 0;
}int main(int argc,char **argv)
{struct person per={"www.100ask.org",10,'A',123};printf("sizeof(char )=%d\n",sizeof(char ));printf("sizeof(int )=%d\n",sizeof(int ));printf("sizeof(char *)=%d\n",sizeof(char *));printf("sizeof(char **)=%d\n",sizeof(char **)); printf("sizeof(struct person)=%d\n",sizeof(struct person)); //push_test("abcd");//push_test("abcd",123); //push_test("abcd",123,per); //push_test("abcd",123,per,'c'); push_test("abcd",123,per,'c',2.79); return 0;
}
运行结果:
注意: float 不行
③。 第二种,访问可变参数方式,使用 宏系统提供
可变参数使用 :
va_list p;
va_start(p, format ); // 移动指针指向到了第一个可变参数,首地址
i = va_arg(p,int); // 取值,移动指针到下一个值首地址
d = va_arg(p,double); // 取值,移动到下一个值首地址
va_arg(p,int); // 注意: 32位系统是4个字节对齐,所以 这里 是int 不是char 读取的是char也
实现代码:
/** push_test.c V1.0 * Copyright (c) 2017 Shenzhen 100ask Technology Co.Ltd.All rights reserved.* http://www.100ask.org* 100ask.taobao.com** 测试平台: ubuntu16.04(64位机器) gcc -m32 -o push_test push_test.c * ubuntu9.10 (32位机器) gcc -o push_test push_test.c * 编译器 : gcc*/#include <stdio.h>
#include <stdarg.h>struct person{char *name;int age;char score;int id;
};
/* *int printf(const char *format, ...); *依据:x86平台,函数调用时参数传递是使用堆栈来实现的 *目的:将所有传入的参数全部打印出来 */
int push_test(const char *format, ...)
{//char *p = (char *)&format;int i;struct person per; char c;double d;va_list p;printf("arg1 : %s\n",format); //==============//p = p + sizeof(char *);va_start(p, format ); /*指针对连续空间操作时: 1) 取值 2)移动指针*/ //i = *((int *)p);//p = p + sizeof(int); i = va_arg(p,int);printf("arg2 : %d\n",i); //============== /*指针对连续空间操作时: 1) 取值 2)移动指针*/ //per = *((struct person *)p); //p = p + sizeof(struct person); per = va_arg(p,struct person);printf("arg3: .name = %s, .age = %d, .socre=%c .id=%d\n",\per.name, per.age, per.score, per.id); //============== /*指针对连续空间操作时: 1) 取值 2)移动指针*///c = *((char *)p);//p = p + ((sizeof(char) + 3) & ~3); c = va_arg(p,int); // 注意: 32位系统是4个字节对齐,所以 这里 是int 不是char printf("arg4: %c\n",c);//============== /*指针对连续空间操作时: 1) 取值 2)移动指针*///d = *((double *)p);//p = p + sizeof(double);d = va_arg(p,double); /*避免"野指针"*///p = (char *)0;va_end( p ); printf("arg5: %f\n",d);return 0;
}int main(int argc,char **argv)
{struct person per={"www.100ask.org",10,'A',123};printf("sizeof(char )=%d\n",sizeof(char ));printf("sizeof(int )=%d\n",sizeof(int ));printf("sizeof(char *)=%d\n",sizeof(char *));printf("sizeof(char **)=%d\n",sizeof(char **)); printf("sizeof(struct person)=%d\n",sizeof(struct person)); //push_test("abcd");//push_test("abcd",123); //push_test("abcd",123,per); //push_test("abcd",123,per,'c'); push_test("abcd",123,per,'c',2.79); return 0;
}
④。 宏实现分析
分析,上面几个宏如何实现 1中的功能的
找到stdarg.h 的几个宏函数,分析,代码如下
/** push_test.c V1.0 * Copyright (c) 2017 Shenzhen 100ask Technology Co.Ltd.All rights reserved.* http://www.100ask.org* 100ask.taobao.com** 测试平台: ubuntu16.04(64位机器) gcc -m32 -o push_test push_test.c * ubuntu9.10 (32位机器) gcc -o push_test push_test.c * 编译器 : gcc*/#include <stdio.h>
//#include <stdarg.h>
typedef char * va_list; // 定义别名
// 功能: 32为系统4字节对齐
// 当sizeof(n)=1/2/4时,_INTSIZEOF 等于4 永远
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
/*va_start(p, format ) ( p = (char *)&format + _INTSIZEOF(format) )( p = (char *)&format + _INTSIZEOF(char *) )( p = (char *)&format + 4 )
*/
//#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
//#define va_arg(ap,t) (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))
#define va_arg(ap,t) (*(t *)(ap = ap + _INTSIZEOF(t), ap - _INTSIZEOF(t)))
/** 整个宏实现2个步骤,取地址,移动指针 , 一个宏如何实现2个表达式的
* (表达式1,表达式2) 最后返回表达式2的值表达式1 :移动指针 、 表达式2: 取址 #define va_arg(ap,t) (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))
ap = ap + _INTSIZEOF(t): 移动指针
*(t *)(ap - _INTSIZEOF(t)): 取址 上面移动到下一个字节了,所以-4 , 然后转化(double*)
*/
#define va_end(ap) ( ap = (va_list)0 ) /**
后面不会用到指针p,把指针p赋值0地址
*/struct person{char *name;int age;char score;int id;
};
/* *int printf(const char *format, ...); *依据:x86平台,函数调用时参数传递是使用堆栈来实现的 *目的:将所有传入的参数全部打印出来 */
int push_test(const char *format, ...)
{//char *p = (char *)&format;int i;struct person per; char c;double d;va_list p;printf("arg1 : %s\n",format); //==============//p = p + sizeof(char *);va_start(p, format ); /*指针对连续空间操作时: 1) 取值 2)移动指针*/ //i = *((int *)p);//p = p + sizeof(int); i = va_arg(p,int);printf("arg2 : %d\n",i); //============== /*指针对连续空间操作时: 1) 取值 2)移动指针*/ //per = *((struct person *)p); //p = p + sizeof(struct person); per = va_arg(p,struct person);printf("arg3: .name = %s, .age = %d, .socre=%c .id=%d\n",\per.name, per.age, per.score, per.id); //============== /*指针对连续空间操作时: 1) 取值 2)移动指针*///c = *((char *)p);//p = p + ((sizeof(char) + 3) & ~3); c = va_arg(p,int);printf("arg4: %c\n",c);//============== /*指针对连续空间操作时: 1) 取值 2)移动指针*///d = *((double *)p);//p = p + sizeof(double);d = va_arg(p,double); /*避免"野指针"*///p = (char *)0;va_end( p ); printf("arg5: %f\n",d);return 0;
}int main(int argc,char **argv)
{struct person per={"www.100ask.org",10,'A',123};printf("sizeof(char )=%d\n",sizeof(char ));printf("sizeof(int )=%d\n",sizeof(int ));printf("sizeof(char *)=%d\n",sizeof(char *));printf("sizeof(char **)=%d\n",sizeof(char **)); printf("sizeof(struct person)=%d\n",sizeof(struct person)); //push_test("abcd");//push_test("abcd",123); //push_test("abcd",123,per); //push_test("abcd",123,per,'c'); push_test("abcd",123,per,'c',2.79); return 0;
}
⑤。 printf函数封装 串口
编译uart.dis 查看 ,默认Makefile
#arm-linux-ld -Ttext 0 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elf
00-cf8 代码段 --- Disassembly of section .text:
cfc-e20 只读段 ----- Disassembly of section .rodata:
8e24-8e30 数据段 ----- Disassembly of section .data:
Disassembly of section .comment: ----- 注释信息段
代码段和只读断是挨着地址上:
但是, 只读断和数据断没有挨着,
8e24已经大于4K内存,可以指定 该地址小于4K,大于 e20即可, Makefile 指定 .data链接地址
arm-linux-ld -Ttext 0 -Tdata 0xe80 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elf
all:arm-linux-gcc -c -o led.o led.carm-linux-gcc -c -o uart.o uart.carm-linux-gcc -c -o lib1funcs.o lib1funcs.Sarm-linux-gcc -c -o my_printf.o my_printf.carm-linux-gcc -c -o main.o main.c#上面是编译为.oarm-linux-gcc -c -o start.o start.S # 链接为可执行程序#arm-linux-ld -Ttext 0 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elfarm-linux-ld -Ttext 0 -Tdata 0xe80 start.o led.o uart.o lib1funcs.o my_printf.o main.o -o uart.elf# 打包为可以烧写程序arm-linux-objcopy -O binary -S uart.elf uart.bin# 反汇编arm-linux-objdump -D uart.elf > uart.dis
clean:rm *.bin *.o *.elf *.dis
uart 之 可变参数相关推荐
- printf 函数使用 可变参数函数实现原理
一. Printf 和scanf 函数格式 Printf 和 scanf 家族函数都属于可变参数函数(variadic function).这种函数需要固定数量的强制参数,后面是数量可变的可选参数. ...
- Python 函数的可变参数(*paramter与**paramter)的使用
Python 函数的可变参数主要有 *paramter与**paramter 可变参数主要有 *paramter的作用 接受任意多个实际参数并放到一个元组中 def people(*people):f ...
- c语言 可变参数的宏,可变参数的宏__ VA_ARGS__的用法
回顾 在[ANSIC几种特殊的标准定义]中我们讲述了比较常用的几项: __FILE__:正在编译文件的路径及文件名 __LINE__:正在编译文件的行号 __DATE__:编译时刻的日期字符串 如&q ...
- java——慎用可变参数列表
说起可变参数,我们先看下面代码段,对它有个直观的认识,下方的红字明确地解释了可变参数的意思: 1 public class VarargsDemo{ 2 3 static int sum(int... ...
- python中lambda 表达式(无参数、一个参数、默认参数、可变参数(*args、**kwargs)、带判断的lambda、列表使用lambda)
如果⼀个函数有⼀个返回值,并且只有⼀句代码,可以使⽤ lambda简化. lambda语法: lambda 参数列表 : 表达式 注意: lambda表达式的参数可有可⽆,函数的参数在lambda表达 ...
- python注解实现原理_Python3注解+可变参数实现
一.说明 1.1 关于注解 关于注解这个东西,最早是在大学学java的时候经常会看到某些方法上边@override之类的东西,一方面不知道其作用但另一方面似乎去掉也没什么影响,所以一直都不怎么在意. ...
- next用法C语言,C语言可变参数的使用
先来个简单的例子:#include #include void test0(int num,...) { va_list ap; va_start(ap, num); while(num--) { p ...
- 9.可变参数创建不可变集合
一.可变参数 1.可变参数介绍 可变参数又称参数个数可变,用做方法的形参出现,那么方法参数个数就是可变的了. 方法的参数类型已经确定,个数不确定,我们可以使用可变参数. 2.可变参数定义格式 修饰符 ...
- Python可变参数
在Python函数中,还可以定义可变参数.顾名思义,可变参数就是传入的参数个数是可变的,可以是1个.2个到任意个,还可以是0个.以数学题为例子,给定一组数字a,b,c--,请计算a2 + b2 + c ...
最新文章
- Python搭建Keras CNN模型破解网站验证码
- 人脸识别引擎SeetaFaceEngine中Alignment模块使用的测试代码
- Microsoft Sql Server Management studio与visual studio 建立连接数据库
- Stanford UFLDL教程 数据预处理
- PaperSize.RawKind 属性
- 实现当前目录下开启CMD
- web服务器 http请求返回 不同返回码的 对应 语意
- 为了金秋那沉甸甸的麦穗,我绝不辜负春天
- 桌面整理工具不显示文件夹_Win10桌面图标显示不正常变成了白色
- 互评Alpha版本—SkyHunter
- 居民小区变配电电力监控系统-安科瑞苏月婷
- kali2020 中文乱码问题
- 电路matlab仿真,电路matlab仿真.doc
- 分享27个高质量前端大佬的油管频道(下)
- 【HDU4960】Another OCD Patient
- iis搭建ftp服务器及身份验证设置
- 不要因为不知,所以设计
- metaq入门部署到实战
- CreateWindow() -- 创建普通的窗口
- 计算机组成原理页表长度,清华计算机组成原理习题课课件习题课1-7.ppt