uart printf 实现 和 c语言 可变参数

②。 第一种访问可变参数方式,使用连续地址的方式

 可变参数入栈,栈内部结构: 

编写代码:  

/*
 *  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.c
	arm-linux-gcc -c -o uart.o uart.c
	arm-linux-gcc -c -o lib1funcs.o lib1funcs.S
	arm-linux-gcc -c -o my_printf.o my_printf.c
	arm-linux-gcc -c -o main.o main.c
	#上面是编译为.o
	arm-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.elf
	 arm-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
	

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值