构建一个arm裸板轻量级的printf

2023-05-16

构建一个arm裸板轻量级的printf

typedef char *  va_list;
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t)    ( *(t *)( ap=ap + _INTSIZEOF(t), ap- _INTSIZEOF(t)) )
#define va_end(ap)      ( ap = (va_list)0 )

va_list 相当于char*
_INTSIZEOF(n),是为了保证arm内部的四字节对齐,后面的公式会根据你的输入类型的字节数输出,如果是小于等于4字节,就输出4字节(前提int是4字节),大于4字节就输出他本身的字节数。
va_start(ap,v) ap是输入指针,v是固定参数,调用他后,指针会指向第一个变参(注意不是固参),因为固参和变参的地址是相邻的,固参地址加上固参的类型所占的字节数,就是第一个变参的首地址
va_arg(ap,t) t为当前变参的类型,他会返回变参的值,并把ap指针指向下一个变参。
va_end(ap) 当ap指针用完后,赋值为0,防止野指针。

int printf(const char* format,...)
{
 va_list ap;
 va_start(ap,format); //ap指向第一个变参
 myprintf( format , ap );
 va_end(ap);    //释放ap指针
 return 0;
}

主要核心函数

static int myprintf( const char* format ,va_list ap)
{
 char lead = ' ';
 int maxwidth = 0;
 /* format是字符串,一个一个分析字符 */
 for( ; *format !='\0';format++)
 {
  /* 如果字符不是%,就不停输出,是%就跳出 */
  if( *format !='%' ){
   outputc(*format);
   continue;
  }
  /* 每次发现%都要初始化这两个 */
  maxwidth = 0;
  lead = ' ';
/* %后有0的话就是填充字符为0,否则为空格 */
  format++;
  if(*format=='0'){
   lead = '0';
   format++;
  }
  /* 处理%后的数字,为输出宽度,写入maxwidth */
  while(*format >= '0' && *format <= '9'){
   maxwidth *= 10;     //处理两位数三位数。。。。。
   maxwidth += (*format - '0'); //*format - '0'就是数字字符的值
   format++;
  }
  /* 把对应的字符,映射到对应的功能 */
  /* 这个va_arg(ap, int)我觉得可以都是int,他是4字节对齐 */
  /* 只有输出长整型的时候才大于4字节 */
  switch( *format ){
   case 'd':OutPutNum( va_arg(ap, int), 10, lead, maxwidth );break;
   case 'o':OutPutNum( va_arg(ap, int), 8, lead, maxwidth );break;
   case 'u':OutPutNum( va_arg(ap, int), 10, lead, maxwidth );break;
   case 'x':OutPutNum( va_arg(ap, int), 16, lead, maxwidth );break;
   case 'c':outputc( va_arg(ap, int) );         break;
   case 's':OutPutStr( (char*)va_arg(ap, int));       break;
   default :outputc(*format);            break;
   
  }
  
 }
 return 0;
}
/*
 n:  要输出的参数
 base: 要输出几进制
 lead: 为填充的字符
 maxwidth:输出宽度
 */
 static int OutPutNum( long n, int base,char lead,int maxwidth )
{
 long m = 0;
 unsigned int count = 0,i;
 /* 定义数组空间,用来存储要输出数字的字符 */
 /* 定义指针s,指向数组空间的尾部 */
 char buffer[MAX_NUMBER_BYTES],*s = buffer + sizeof(buffer);
 /* 先让s指向的地址减一,再赋值 (我觉得这不减可以)*/
 *--s = '\0';
 /*确保m为正*/
 if(n<0){
  m = -n;
 }
 /* 把要输出的数字转化为字符,并且更换进制 count来计数这个数有几位*/
 do{
  *--s = AscllNum[m%base];
  count++;
 }while((m/=base) != 0 );
 /* 输出有宽度,并且数字宽度小于输出宽度 */
 /* 剩下的位置填充字符 */
 if( maxwidth && count<maxwidth){
   for( i=maxwidth - count;i;i-- ){
   *--s = lead;
   }
 }
 /* 添加符号 */
 if( n<0 ){
  *--s = '-';
 }
 return OutPutStr(s)}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

构建一个arm裸板轻量级的printf 的相关文章

  • ARM 汇编分支到寄存器或内存内部的地址

    我想知道在 ARM 汇编中我可以使用哪条指令分支到存储在某个内存地址中的地址或标签 例如 我们可以使用B LABEL来跳转到LABEL 但现在目的地只能在运行时知道 并且它存储在某个已知的内存位置 是否有类似 B 地址 的东西 Thanks
  • C 中的类型转换会变得香蕉吗? [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 看来 C 和我对这里的预期输出存在分歧 I have struct r struct int r i float r f
  • ARM Linux 如何模拟 PTE 的脏位、访问位和文件位?

    As per pgtable 2 level h https git kernel org cgit linux kernel git torvalds linux git tree arch arm include asm pgtable
  • scanf("%d", &value) 中的字符输入[重复]

    这个问题在这里已经有答案了 简而言之 我的代码是 include
  • 手臂“版本”之间的差异? (仅限 ARMv7)

    基本上我想知道ARMv7l和ARMv7之间的区别hl 我有一个带有armv7l的arm处理器 并且有很多armv7的rpmhl 我完全不知道我必须搜索什么才能获得相关信息 这个 后缀 叫什么 还有其他类型吗 他们的做法有何不同 我假设它指示
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • 使用 ncurses 处理转义序列? printf 是否处理转义序列?

    我的程序从网络读取一些文本数据 例如 Hello 033 1 34mworld 033 0m and bla bla bla n 当程序使用prinf输出该字符串时 world 一词是蓝色的 但是当我将 ncurses 接口与 wprint
  • DSP 库 - RFFT - 奇怪的结果

    最近我一直在尝试在我的STM32F4 Discovery评估板上进行FFT计算 然后将其发送到PC 我已经调查了我的问题 我认为我对制造商提供的 FFT 函数做错了 我正在使用 CMSIS DSP 库 现在我一直在用代码生成样本 如果工作正
  • Linux malloc() 在 ARM 和 x86 上的行为是否不同?

    这个网站上有很多关于内存分配的问题 但是我 找不到专门解决我的问题的人 这 问题 https stackoverflow com questions 19148296 linux memory overcommit details似乎最接近
  • 如何在 Android 设备上运行 VS Code [重复]

    这个问题在这里已经有答案了 我有 Galaxy Tab S6 它具有替代笔记本电脑的很酷的功能 例如连接鼠标和键盘 但不幸的是它运行 Android 操作系统 并且没有很多开发应用程序可用于 Android 所以我想是否有一个选项可以在至少
  • 如何使用 printf 自定义自定义类型的输出?

    我已经阅读了很多内容专家 F 并正在致力于构建一个实际的应用程序 在调试时 我已经习惯了传递这样的 fsi 命令 以使 repl 窗口中的内容清晰可见 fsi AddPrinter fun x myType gt myType ToStri
  • Java中printf左对齐

    当我运行该程序时 阶乘值右对齐 有没有办法让它左对齐 同时保持中间 50 个空格 public class Exercise 5 13 public static void main String args int numbers 1 2
  • 使用 OpenMP 时无用的 printf 没有加速

    我刚刚编写了第一个 OpenMP 程序 它并行化了一个简单的 for 循环 我在双核机器上运行代码 发现从 1 个线程变为 2 个线程时速度有所提高 然而 我在学校 Linux 服务器上运行相同的代码并没有看到加速 在尝试了不同的事情之后
  • 了解 ctags 文件格式

    我使用 Exhuberant ctags 来索引我的 c 项目中的所有标签 c project 是 Cortex M7 微控制器的嵌入式软件 结果是一个标签文件 我正在尝试阅读该文件并理解所写的内容 根据我找到的 ctags 和 Exhub
  • 在linux x86平台上学习ARM所需的工具[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我有一个 x86 linux 机器 在阅读一些关于 ARM 的各种信息时 我很好奇 现在我想花一些时间学
  • 字符串格式化表达式 (Python)

    字符串格式化表达式 This is d s example 1 nice 字符串格式化方法调用 This is 0 1 example format 1 nice 我个人更喜欢方法调用 第二个示例 以提高可读性 但由于它是新的 因此随着时间
  • 了解 U-Boot 内存占用

    我不明白加载 U Boot 时 RAM 中发生了什么 我正在开发 Xilinx Zynq ZC702 评估套件 并尝试使用 U Boot 在其上加载 Linux 内核 于是我使用Xilinx工具Vivado和SDK生成了一个BOOT bin
  • gdb 不会从外部架构读取核心文件

    我正在尝试在 Linux 桌面上读取 ARM 核心文件 但似乎无法找出我的核心文件 有什么方法可以指示 gdb 我的核心文件是什么类型吗 file daemon daemon ELF 32 bit LSB executable ARM ve
  • saber sd 如何在没有 SPL 的情况下直接从 uboot 启动

    sabre sd 基于 imx 6 最大内部 RAM 约为 150Kb 然而 uboot 足够大 可以容纳在这个空间中 在这个场景中事情是如何进行的 https community freescale com docs DOC 95015
  • 直接在 ARM 目标上调试单声道应用程序

    我最近在 BeagleBone 嵌入式 ARM 设备上安装了 Mono 希望通过 USB 连接 Kinnect 传感器并使用 C Mono 控制它 我想知道 Mono 我正在使用 MonoDevelop 但我想这个问题也适用于 VS 是否允

随机推荐