printf如何按二进制格式打印

2023-05-16

printf函数:
int printf(const char *format, ...)
  • format -- 这是字符串,包含了要被写入到标准输出 stdout 的文本。

                      它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。

                      format 标签属性是 %[flags][width][.precision][length]specifier,如下:

格式字符意义
d以十进制形式输出带符号整数(正数不输出符号)
o以八进制形式输出无符号整数(不输出前缀0)
x,X以十六进制形式输出无符号整数(不输出前缀Ox)

我们可以看到printf的format支持十进制、8进制、16进制,就是没有二进制,所以嵌入式C开发中经常会遇到位操作,debug时为了方便查看结果,需要二进制查看,我们看一下如何打印2进制。

首先我们看一下一个数据如何换算成二进制:

 

一个整数不断的除以2,每次得到的余数即构成了二进制数,所以这里首先想到使用递归来实现。

  • 方法1: 递归实现
void print_binary(unsigned int number) {
    if (number >> 1) {
        print_binary(number >> 1);
    }
    putc((number & 1) ? '1' : '0', stdout);
}
  • 方法2:利用宏定义打印

PRINTF_BYTE_TO_BINARY_INT8直接依次从高到低位取出数据变成字符使用%c打印,如果16位,则调用2次PRINTF_BYTE_TO_BINARY_INT8,高位右移8位按照PRINTF_BYTE_TO_BINARY_INT8打印,低位直接打印,32位和64位依次类推。

 

这个算法思路简单清晰,相比上面的递归,效率很高,值得推荐。

 

/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i)    \
    (((i) & 0x80ll) ? '1' : '0'), \
    (((i) & 0x40ll) ? '1' : '0'), \
    (((i) & 0x20ll) ? '1' : '0'), \
    (((i) & 0x10ll) ? '1' : '0'), \
    (((i) & 0x08ll) ? '1' : '0'), \
    (((i) & 0x04ll) ? '1' : '0'), \
    (((i) & 0x02ll) ? '1' : '0'), \
    (((i) & 0x01ll) ? '1' : '0')

#define PRINTF_BINARY_PATTERN_INT16 \
    PRINTF_BINARY_PATTERN_INT8              PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
    PRINTF_BYTE_TO_BINARY_INT8((i) >> 8),   PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
    PRINTF_BINARY_PATTERN_INT16             PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
    PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64    \
    PRINTF_BINARY_PATTERN_INT32             PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
    PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */

#include <stdio.h>
int main() {
    long long int flag = 1648646756487983144ll;
    printf("My Flag "
           PRINTF_BINARY_PATTERN_INT64 "\n",
           PRINTF_BYTE_TO_BINARY_INT64(flag));
    return 0;
}

 

  • 方法3: itoa实现:

有这么一个函数itoa, 它将整数转化为字符串,它不是标准的C库函数,最早出现在Kernighan 和Ritchie《The C Programming Language》这本书中:

/* reverse:  reverse string s in place */
void reverse(char s[])
{
    int c, i, j;

    for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
        c = s[i];
        s[i] = s[j];
        s[j] = c;
    }
}

/* itoa:  convert n to characters in s */
void itoa(int n, char s[])
{
    int i, sign;

    sign = n;
    i = 0;
    do {        /* generate digits in reverse order */
        s[i++] = abs(n % 10) + '0';     /* get next digit */
    } while (n /= 10);                  /* delete it */
    if (sign < 0)
        s[i++] = '-';
    s[i] = '\0';
    reverse(s);
}

它只支持了十进制,它的思路很简单,就是对n求余,得到尾数,然后n舍弃尾数再求余又得到一个尾数,依次类推,每个尾数使用ASCII值转换为字符,即直接使用基数'0' 加上偏移即可。这样得到的字符串是一个逆序的,需要翻转一下。翻转函数就很简单了,就是一个循环,2个变量i,j 一个从头部递增,一个从尾部递减,交换值即可。

 

我们来看一下几个库对该函数的实现:

Windows的 c runtime Library (CRT)的stdlib库中实现了itoa函数,

char *  itoa ( int value, char * str, int base );

但遗憾的是并没有找到微软的这个库的源代码。

不过,在glibc 2.28版本中找到了itoa的实现,大家可以研究一下:

  • stdio-common/_itoa.c
  • sysdeps/generic/_itoa.h

我们看一下同济大学陈老师和他的精英学子们重构的UNIX V6PP 中如何实现的:

char* _itoa( unsigned long value, int neg_sign, char* buffer, int radix)
{
	char* bret = buffer;
	unsigned int num = value;
	char* bufferStart = 0;
	
	if ( !buffer || radix <= 0 || radix > 16 ) 
		return 0;
	
	if ( neg_sign )
	{
		*buffer++ = '-';
	}
	
	bufferStart = buffer;
	*buffer = '0'; /* if num == 0 then ...*/
	while ( num ) 
	{
		char ch = num % radix;
		*buffer++ =  ch + ( ch < 10 ? '0' : 'a' - 10 );
		num /= radix;
	}
	if ( value ) *buffer = 0;
	else *++buffer = 0;

	buffer--;
	while ( bufferStart < buffer ) /* reserve the string */
	{
		char tch = *bufferStart;
		*bufferStart = *buffer;
		*buffer = tch;
		bufferStart++;
		buffer--;
	}
	return bret;	
}

char* itoa( long value, char* buffer, int radix )
{
	int s =  value < 0 ? 1 : 0;
	if ( s ) value = -value;
	return _itoa( value, s, buffer, radix );
}
char* uitoa( unsigned long value, char* buffer, int radix )
{
	return _itoa( value, 0, buffer, radix );
}

我们可以看到他们移植重构的这段代码,思路和《The C Programming Language》这本书中的思路是一致的,不过他们支持了多进制,算法简单,逻辑清晰。

我们可以看到代码中使用了一个bufferStart指针指向buffer,首先给了一个初始值,保证num为0时能够正确输出;

然后在while循环中利用进制转换方式,即对该进制取余得到尾部数据,然后该进制的基数字符加上得到的余数作为偏移,就可以得到ASCII的字符;

这里16进制以上超出了10,ASCII表中0-9和a-f并不连续,所以转换为16进制时如果得到的尾数>=10的需要以'a' - 10作为基数;

同理不断移除尾部数据得到尾部字符,直到数据为0;

如果要转换的数据大于0,则直接添加结束符,如果数据等于0,保留初始值'0',后移一位添加结束符。

最后翻转字符串。

题外话:可以看到这里有部分代码使用了驼峰,和其他部分有风格混搭,我们在代码工程中需要坚持一种风格。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

printf如何按二进制格式打印 的相关文章

  • jmeter察看结果树的响应数据时显示乱码

    找到jmeter的安装路径 xff08 即解压路径 xff09 打开apache jmeter 4 0 bin jmeter properties文件 搜索 encoding 关键字 xff0c 找到如下配置 xff1a The encod
  • class 和 struct的区别

    class 和 struct 最本质的区别 class 是引用类型 xff0c 它在堆中分配空间 xff0c 栈中保存的只是引用 xff1b 而 struct 是值类型 xff0c 它在栈中分配空间 什么是class class xff08
  • 第一周——总体了解STM32以及开发环境搭建

    什么是STM32 意法半导体 xff08 ST xff09 集团于1988年6月成立 xff0c 是由意大利的SGS微电子公司和法国Thomson半导体公司合并而成 STM32系列基于专为要求高性能 低成本 低功耗的嵌入式应用专门设计的AR
  • 【ros下激光雷达的简单使用】(1)

    雷达简单使用方法 xff1a 思蓝科技S2的激光雷达 查看硬件是否连接成功 xff1a 使用lsusb wpf 64 wpfpc lsusb Bus 002 Device 001 ID 1d6b 0003 Linux Foundation
  • AMD CPU 电脑突然画面声音突然卡顿,卡碟声,画面撕裂

    有时候会突然卡顿个一两秒 xff0c 然后自己好 xff0c 如果主板买的早 xff0c 没更新过BIOS版本 xff0c 可能是因为AMD的fTPM设置有个BUG xff0c 开启之后有概率会随机卡顿 xff0c 各大厂商最新的主板驱动应
  • STL —— vector,list,deque,使用与优缺点比较

    关于vector list deque 已经做过介绍 xff0c 本文是对三种容器的优劣做出比较 下面是vector list deque的博客链接 vector list deque vector list对比 底层结构 动态顺序表 xf
  • android手机版tcp或者udp通讯测试工具,可以用于工业设备或者系统开发时间测试tcp或是udp连接通讯是否正常工作

    TUtool 介绍 由于工作需要一款安卓的tcp udp测试工具 xff0c 而市场里没有或者不好用 xff0c 或者都是广告 xff0c 现在个人开发者又不让发布应用了 xff0c 小巧好用不收集用户信息的不收费没有广告的小工具只能自己用
  • microhard p900数传配置方法

    配置好的两个 xff08 多个 xff09 数传电台可以通过串口直接相互通讯 xff0c 两个 xff08 多个 xff09 数传之间无线连接 数传电台可以配置多种通讯方式 xff1a 点对点 点对多 mesh组网 xff08 电台数量 2
  • boost.asio异步调用使用智能指针

    boost asio中的异步async 函数需要传入回调函数参数 xff0c 如果回调函数使用lamda表达式 xff0c 在 capture 列表中传入智能指针 xff0c 智能指针会生效吗 xff1f 在async connect调用之
  • sscanf 格式化输入 的关键 VS2010\VC\crt\src\input.c

    VS2010 VC crt src ctype h define ischartype l Char Flag Locale Locale 61 NULL amp amp locale t Locale gt locinfo gt mb c
  • VS万能头文件添加方法(整理版)

    本文所使用的技术来自B站up主 昕辰丶 首先按照图中箭头找到VS在磁盘中的位置 按照箭头操作 先在搜索中输入msvc 然后点击Tools结尾的MSVC文件夹 点击这唯一的文件夹 打开include文件夹 新建一个文件夹并且命名为 bits
  • 集美大学-浙大版《C语言程序设计实验与习题指导(第3版)》

    这是我2020年大一入学前写的代码 xff0c 当时的测试点是全过的 xff0c 现在可能有些测试点过不去了 xff0c 如果有发现测试点过不去的 xff0c 可以联系我修改一下 xff0c 希望大家共同进步 xff08 工作量有点大 xf
  • 集美大学 - 2840 - 实验7-1 - 编程题

    实验7 1 1 一维数组 简化的插入排序 本题要求编写程序 xff0c 将一个给定的整数插到原本有序的整数序列中 xff0c 使结果序列仍然有序 输入格式 xff1a 输入在第一行先给出非负整数N xff08 lt 10 xff09 xff
  • 听劝,不要试图以编程为基础去学习网络安全

    目录 一 网络安全学习的误区1 不要试图以编程为基础去学习网络安全2 不要刚开始就深度学习网络安全3 收集适当的学习资料4 适当的报班学习 二 学习网络安全的些许准备1 硬件选择2 软件选择3 外语能力 三 网络安全学习路线第一阶段 xff
  • 集美大学 - 2840 - 实验8 - 编程题

    实验8 1 9 指针 输出学生成绩 本题要求编写程序 xff0c 根据输入学生的成绩 xff0c 统计并输出学生的平均成绩 最高成绩和最低成绩 建议使用动态内存分配来实现 输入格式 xff1a 输入第一行首先给出一个正整数N xff0c 表
  • vscode中文乱码问题及几种常见的解决方案

    问题及原因 问题原因 xff1a 代码文件的字符编码格式为UTF 8 xff0c 但是terminal的字符编码格式为GBK 解决思路 xff1a 统一代码文件和terminal的字符编码格式 解决办法 说明 xff1a 以下的解决方案是针
  • 集美大学 - 2840 - 实验11-2 - 函数题

    实验11 2 1 链表 建立学生信息链表 本题要求实现一个将输入的学生成绩组织成单向链表的简单函数 函数接口定义 xff1a span class token keyword void span span class token funct
  • python正则表达式

    python正则表达式 match函数 re match尝试从字符串的起始位置匹配一个模式 xff0c 如果不是起始位置匹配成功的话 xff0c match 就返回none 函数语法 xff1a re span class token pu
  • 轻松解决VS配置OpenCV环境及导出OpenCV的VS项目模板

    一 OpenCV配置 1 下载OpenCV 点击进入下载OpenCV的官网界面 这里以Windows为例 xff0c 其他同理 xff08 可直接下载最新 xff09 2 提取OpenCV 在这里浅说一句 xff0c 为了方便环境配置文件管
  • 最大子段和问题

    以下给出具体代码 xff1a span class token macro property span class token directive hash span span class token directive keyword i

随机推荐

  • 如何简单又好看地美化你的Ubuntu界面

    起因 最近使用Ubuntu界面实属是审美疲劳了 xff0c 使用老版本的一大问题就是 界面太难看了 秉持新手学习最好是用老一点的稳定版本的观念 Ubuntu旧版本使用或使用过的人非常非常多 xff0c 学习的过程中你一旦出现什么问题互联网上
  • 【实战】物联网安防监控项目【2】———boa服务器的移植

    一 boa服务器的移植 1 源码下载 1 1 boa简介 xff1a 其可执行代码只有大约60KB左右 xff0c Boa是一个单任务的HTTP服务器 xff0c Boa只能依次完成用户的请求 xff0c 而不会fork出新的进程来处理并发
  • 【实战】物联网安防监控项目【4】———从网页上控制A9的LED灯

    前言 学习了一个新知识 xff0c 当然要记录一下啦 这两天学习了boa服务器 cgic标准库和html标签语言 xff0c 又双叕解锁一个嵌入式的新玩法 cgic库是沟通C语言和html网页编程语言的一座桥梁 xff0c 通过在linux
  • 【实战】物联网安防监控项目【5】———把模拟数据传输到web网页、web显示mjpeg-streamer视频图像

    1 模拟数据传输到web 为了把硬件传感器上的数据上传到web网页 xff0c 我们需要在跑linux服务器的开发板上写一个应用程序 xff0c 并创建出几个线程来收集传感器检测到的数据 xff0c 通过进程 线程间通信 boa与cgic库
  • HttpGet Digest授权认证

    工具类 xff1a compile com burgstaller okhttp digest 1 13 import android span class hljs preprocessor content span span class
  • ubuntu下git push失败error: 无法推送一些引用到 ‘xxx ‘解决方法

    如果你在Ubuntu下使用git push上传你的代码到gitee xff0c 突然出现一行报错 xff1a To git 64 gitee com imysy twenty two thread pool test git rejecte
  • 【Linux驱动开发】并发控制机制:原子操作、自旋锁、信号量、互斥锁详解

    并发控制机制 首先我们来了解一下 操作系统的并发性 这个概念 xff1a 操作系统的并发性 concurrence xff1a 指的是两个或者两个以上事件在同一时间间隔内发生 xff0c 即这个设备一会执行这个事件一会执行那个事件 xff0
  • STM32F051K8U6按键中断实例

    引言 最近要开始做毕设了 xff0c 准备用STM32做一个平衡小车 xff0c 好久没做过STM32的裸机项目了 xff0c 做几个项目练练手 xff0c 复习一下 本例程使用STM32CubeMX配套hal库来实现按键中断和串口中断 芯
  • STM32库函数笔记分享

    之前刚开始自学的部分STM32笔记放出 xff0c 希望对新入门STM32和想要复习库函数的小伙伴们起到帮助 建立工程 1 寄存器操作方式 需要不断地查手册来了解每一位是干什么用的 优点 xff1a 代码简介 xff1b 缺点 xff1a
  • rc.exe not found.(完美解决,亲测有效)

    完美解决rc exe not found 报错出错原因解决方法完美解决 报错 这两天安装了vs2015和IVF2016 xff0c 安装完之后在运行程序的时候一直会出现rc exe not found xff0c 重新生成解决方案后还是一样
  • 单片机与上位机通过串口通信--笔记

    定义 先说什么是串口 xff1f xff08 1 xff09 他是一种通信接口 xff0c 单片机 IO 口上的复用功能 xff0c 上位机 xff08 电脑 xff09 和下位机 xff08 开发板 xff09 之间的数据传输 xff08
  • Qt 的Cmake方式如何创建资源文件

    传统的qmake创建的工程有pro qrc xff0c 但是如果使用cmake方式创建的工程就没有这两个东西 xff0c 我们公司就是在linux下使用cmake创建的Qt工程 xff0c 没有pro也看不到qrc xff0c 想在ui界面
  • 理解ROS Topic 通信频率背后的机制

    Topic是ROS的三种通信方式中最为基本 也是常用的一种 本文对于ROS的Topic通信背后的数据吞吐机制做一个较为详细 深入的介绍 Publisher ROS中发布一个topic的函数是这样的 ros span class token
  • Linux应用层例程4 串口应用编程

    本小节我们来学习 Linux 下串口应用编程 xff0c 串口 xff08 UART xff09 是一种非常常见的外设 xff0c 串口在嵌入式开发领域当中一般作为一种调试手段 xff0c 通过串口输出调试打印信息 xff0c 或者通过串口
  • Linux应用层例程7 CAN 应用编程基础

    CAN 是一种多主方式的串行通讯总线 xff0c 基本设计规范要求有高的位速率 xff0c 高抗电磁干扰性 xff0c 而且能够检测出产生的任何错误 经过几十年的发展 xff0c 现在 xff0c CAN 的高性能 高可靠性以及高实时性已被
  • 使用Socket方式调用HttpWebApi获取数据

    背景 xff1a 最近有一个需求 xff0c 单片机需要调用服务端Api获取数据 xff0c 因为一些原因单片机只能使用TCP方式 xff1b 作为服务端开发人员提供Demo 代码如下 xff08 这里用C 语言演示 xff09 using
  • git branch 和 tag的区别

    1 git branch 和 tag的区别 xff1f 1 git branch 上的修改可以保留 xff0c 例如在某个branch上commit一个新的节点 checkout到其它branch后commit的节点不会丢 2 git ta
  • 测线仪正确使用方法图解1

    测线仪正确使用方法图解1 测线仪正确使用方法图解2 测线仪正确使用方法图解3 测线仪正确使用方法图解 xff0c 我们来使用莱视威测试仪YN891 xff0c 先说说第一个功能 xff0c 测线 xff0c 首先 xff0c 我们打开旁边的
  • Git仓库分支(Branch)和标签(Tag)

    仓库的分支 Branch 规范 xff0c 影响到每个团队的工作流的一致性 xff1b 标签 Tag 便于开发团队 测 试团队和其他团队识别每个项目的版本 xff0c 特别是在协同处理线上问题的时候 xff0c 大家可以非常清楚 地知道线上
  • printf如何按二进制格式打印

    printf函数 xff1a int printf const char format format 这是字符串 xff0c 包含了要被写入到标准输出 stdout 的文本 它可以包含嵌入的 format 标签 xff0c format 标