百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

C语言将十六进制数据转换为字符串

liebian365 2024-10-20 09:57 48 浏览 0 评论

程序开发可能会遇到要将收到的数据包(十六进制数)转换为字符串,可以使用自定义函数在不使用字符串库函数的情况下实现转换,可以用于APP版本号、日期、写日志或者其他特殊用法。今天主要是以实际例子简单介绍不使用库函数实现十六进制数据转换为字符串以及字符串的复制。


1.十六进制数据转字符串的hex2str函数

/***********************************************************************
函数名称:hex2str
函数功能:将十六进制数转换为字符串
输入参数:
    hexdata 表示输入的十六进制数
    s 表示字符指针指向存储的结果字符串 
    length 表示输入十六进制的数据的长度 
************************************************************************/
static void hex2str(unsigned int hexdata, char* s, int length)
{
    int k;
    s[length] = 0;
    /* 一位一位取十六进制数 一个十六进制数 = 四个二进制数  
    hexdata >>= 4  每次运算完一个十六进制转字符之后右移4位二进制 */
    for (k = length - 1; k >= 0; k--, hexdata >>= 4)
    {
      /*hexdata & 0xF 是将数据的最低的四位二进制数取出 即取出最低位的十六进制数
    例如 0x91&  0x0F = bin 1001 0001 &  bin 0000 1111=bin 0000 0001=0x1 */ 


        if ((hexdata & 0xF) <= 9)/* 对十六进制中的数据进行处理 */
           {
                s[k] = (hexdata & 0xF) + '0';/*数字变成字符,只需要加上字符0的ASCLL值 */
           }
        else
            {
                s[k] = (hexdata & 0xF) + 'A' - 0x0A;/*字母变成字符,只需要加上字符A的ASCLL值
        0xB + 'A' - 0x0A = 1+'A' = 'B' 十六进制中大小写字母表示的含义相同
        0xb = 0xB*/
            }
    }
}

2.测试程序1

程序

#include <stdio.h> //加载头文件 


/***********************************************************************
函数名称:hex2str
函数功能:将十六进制数转换为字符串
输入参数:
    hexdata 表示输入的十六进制数
    s 表示字符指针指向存储的结果字符串 
    length 表示输入十六进制的数据的长度 
************************************************************************/
static void hex2str(unsigned int hexdata, char* s, int length)
{
    int k;
    s[length] = 0;
    /* 一位一位取十六进制数 一个十六进制数 = 四个二进制数  
    hexdata >>= 4  每次运算完一个十六进制转字符之后右移4位二进制 */
    for (k = length - 1; k >= 0; k--, hexdata >>= 4)
    {
      /*hexdata & 0xF 是将数据的最低的四位二进制数取出 即取出最低位的十六进制数
    例如 0x91&  0x0F = bin 1001 0001 &  bin 0000 1111=bin 0000 0001=0x1 */ 


        if ((hexdata & 0xF) <= 9)/* 对十六进制中的数据进行处理 */
           {
                s[k] = (hexdata & 0xF) + '0';/*数字变成字符,只需要加上字符0的ASCLL值 */
           }
        else
            {
                s[k] = (hexdata & 0xF) + 'A' - 0x0A;/*字母变成字符,只需要加上字符A的ASCLL值
        0xB + 'A' - 0x0A = 1+'A' = 'B' 十六进制中大小写字母表示的含义相同
        0xb = 0xB*/
            }
    }
}


int main() 
{
  unsigned int a = 0xAbCD3123;/*定义数据*/
  unsigned int b = 0x20240214;
  unsigned int c = 0x20240214U;
  char str[9]="00000000";/*存储结果*/
  char *s;
  s = &str[0];
  int len = 8;
  printf("%s\n",str);
  hex2str(a,s,len);
  printf("%s\n",str);
  hex2str(b,s,len);
  printf("%s\n",str);
  hex2str(c,s,len);
  printf("%s\n",str);  
  system("pause");/*让控制窗口停留而不是一闪而过 */
  return 0;
 }

运行结果


3.测试程序2

#include <stdio.h> //加载头文件 
#define TIME (0x20240214U) //宏定义 


/***********************************************************************
函数名称:hex2str
函数功能:将十六进制数转换为字符串
输入参数:
    hexdata 表示输入的十六进制数
    s 表示字符指针指向存储的结果字符串 
    length 表示输入十六进制的数据的长度 
************************************************************************/
static void hex2str(unsigned int hexdata, char* s, int length)
{
    int k;
    s[length] = 0;
    /* 一位一位取十六进制数 一个十六进制数 = 四个二进制数  
    hexdata >>= 4  每次运算完一个十六进制转字符之后右移4位二进制 */
    for (k = length - 1; k >= 0; k--, hexdata >>= 4)
    {
      /*hexdata & 0xF 是将数据的最低的四位二进制数取出 即取出最低位的十六进制数
    例如 0x91&  0x0F = bin 1001 0001 &  bin 0000 1111=bin 0000 0001=0x1 */ 


        if ((hexdata & 0xF) <= 9)/* 对十六进制中的数据进行处理 */
           {
                s[k] = (hexdata & 0xF) + '0';/*数字变成字符,只需要加上字符0的ASCLL值 */
           }
        else
            {
                s[k] = (hexdata & 0xF) + 'A' - 0x0A;/*字母变成字符,只需要加上字符A的ASCLL值
        0xB + 'A' - 0x0A = 1+'A' = 'B' 十六进制中大小写字母表示的含义相同
        0xb = 0xB*/
            }
    }
}
/***********************************************************************
函数名称:strc
函数功能:将两个字符串拼接 
输入参数:
    str1 表示指向字符串1的字符指针 ,结果存储在字符串1中 
    str2 表示指向字符串2的字符指针  


************************************************************************/
static void strc(char *str1,char *str2)
{


   int i=0,j=0;
   while(str1[i]!='\0')
   {
     i++;
   }
    while(str2[j]!='\0')
   {
     str1[i++]=str2[j++];
   }
   str1[i]='\0';


}


int main()
{
    unsigned int  i = 0;
    char Version_num[9]="00000000";
    char Version_numF[10]="0000F0000";
    char Version[17] = "YUNLONGV";
    char *s;
    s = &Version_num[0];
    unsigned int len = 8;
    hex2str( TIME,s, len);
    printf("%s\n",Version_num);
    for(i = 0;i<4;i++)
    {
        Version_numF[i] = Version_num[i];
    }
    for(i = 5;i<9;i++)
    {
        Version_numF[i] = Version_num[i-1];
    }
    printf("%s\n",Version_numF);
    strc(Version,Version_numF);
    printf("%s\n",Version);
    printf("\n");
    system("pause");/*让控制窗口停留而不是一闪而过 */
    return 0;


}

运行结果

4.程序改进

上述的程序在实际汽车嵌入式的单片机运行时会出现以下问题:

问题1:在程序每次被周期调度时,都会执行strc字符串复制函数,导致字符数组超出大小,溢出影响CAN通信。


问题2:定义的字符数组放在了函数内容里面,当函数执行完之后,内容会被释放,指针返回的是随机的内容。

问题3:程序定义的变量和内容太多。

解决方案:简化程序,直接对字符数组进行赋值操作,利用右移函数直接将十六进制数字转换为相应的数字。

程序

#include <stdio.h>
#define TIME (0x20240214U) //宏定义 
typedef unsigned char       uint8;
typedef unsigned long       uint32;
static void strc(char *arr1,char *arr2)
{


   int i=0,j=0;
   while(arr1[i]!='\0')
   {
     i++;
   }
    while(arr2[j]!='\0')
   {
     arr1[i++]=arr2[j++];
   }
   arr1[i]='\0';
   
}


 static void hex2str(uint32 data, char* s, int len)
{
     int i;
     s[len] = 0;
     for (i = len - 1; i >= 0; i--, data >>= 4)
     {
         if ((data & 0xf) <= 9)
            {
                 s[i] = (data & 0xf) + '0';
            }
         else
             {
                 s[i] = (data & 0xf) + 'A' - 0x0a;
             }
     }
 }
char Version[17] = "YUNLONGV";//不能放在函数内部,不然程序结束之后内存会被释放 
const uint8 * GetSoftwareVersionInformation(void)
{
   uint8  i = 0;
     char Version_num[8]="SW00000";
     char Version_numF[10]="0000F0000";
     
     char *s;
     s = &Version_num[0];
     uint8 len = 8;
     hex2str( TIME,s, len);
     printf("%s\n",Version_num);
     for(i = 0;i<4;i++)
     {
         Version_numF[i] = Version_num[i];
     }
     for(i = 5;i<9;i++)
     {
         Version_numF[i] = Version_num[i-1];
     }
     printf("%s\n",Version_numF);
     strc(Version,Version_numF);
//     printf("%s\n",Version);
    return ((const uint8 *)  Version);
}
char Version1[17] = "YUNLONGVxxxxFxxxx";
const uint8 * GetSoftwareVersionInformation1(void)
{
  uint8 i = 0;
  for(i = 0;i<8;i++)
  {
      if(i<4) 
      {
      Version1[i+8] = '0'+(TIME>>((7-i)*4)&(0x0FU));
      }
      else
      {
        Version1[i+9] = '0'+(TIME>>((7-i)*4)&(0x0FU));  
      }  
  }


  return ((const uint8 *)  Version1);
}
int main()
{
  printf("%s\n",GetSoftwareVersionInformation());
  printf("%s\n",GetSoftwareVersionInformation());//程序每调用一次就会累加一次 溢出  要让程序只执行一次 
  printf("%s\n",GetSoftwareVersionInformation1()); 
  system("pause");
  return 0;
 } 


5.程序涉及的基础知识

(1)c语言static关键字的作用

(1)static修饰全局变量:使用static修饰全局变量,该变量将变成静态全局变量,只能在该c文件中使用,从而限定了作用域。一般的全局变量是可以在整个工程文件(包含了多个*.c文件),也就是在一个c文件中定义的全局变量,需要在其他的c文件中使用时需要使用extern关键字声明。

(2)static修饰局部变量:局部变量就是在函数内部定义的变量,当使用static修饰局部变量后,该变量就变成了静态的局部变量,作用域会持续到整个程序结束。一般的局部变量在离开被定义的函数之后,内存就会被释放。

(3)static修饰函数:当使用static修饰函数时,这个函数就变成了静态函数,作用域就仅限于该c文件中,而不能被项目中其他的c文件调用,这样可以减少团队开发时使用相同的函数名定义不同的功能。

(2)system("pause")

system("pause")是将正在执行的程序暂停执行,在控制台窗口敲下任意键之后程序会继续执行,这样可以让控制台窗口不会一闪就关闭。

(3)>>=运算

/*
1.化十进制数为(注意了)对应的二进制数,对应指格式对应
2.通通右移,正数左补0,负数左补1,右边丢弃
3.化为十进制数
举例:short int a=8;a=a>>1;




1.a=0 000 1000
2.右移一位后:a= 0 000 100
3.补0:a=0 000 0100
4.化为十进制数:a=4
*/

(4)数组名

C语言中的数组名有两种含义,一是标识数组,二是代表数组的首地址,数组名的实质就是数组的首地址。


6.参考内容

[1] CSDN作者A鱼翔浅底A的文章《>> << 0xf 等用法》,文章链接为:

https://blog.csdn.net/wangdamingll/article/details/53434098

[2]CSDN作者QQ851301776的文章《C语言把十六进制数据转换为字符串》,文章链接为:

《https://blog.csdn.net/weixin_43155199/article/details/123276021》

[3] CSDN作者二十又的文章《【c语言】实现两个字符串的连接(自己定义函数)》,文章链接为:

https://blog.csdn.net/qq_62755550/article/details/122095381


本文内容来源于网络,仅供参考学习,如内容、图片有任何版权问题,请联系处理,24小时内删除。


作 者 | 郭志龙

编 辑 | 郭志龙
校 对 | 郭志龙

相关推荐

月薪 4K 到 4W 的运维工程师都经历了什么?

运维工程师在前期是一个很苦逼的工作,在这期间可能干着修电脑、掐网线、搬机器的活,显得没地位!时间也很碎片化,各种零碎的琐事围绕着你,很难体现个人价值,渐渐的对行业很迷茫,觉得没什么发展前途。这些枯燥无...

计算机专业必须掌握的脚本开发语言—shell

提起Shell脚本很多都有了解,因为无论是windows的Dom命令行还是Linux的bash都是它的表现形式,但是很多人不知道它还有一门脚本编程语言,就是ShellScript,我们提起的Shel...

Linux/Shell:排名第四的计算机关键技能

除了编程语言之外,要想找一份计算机相关的工作,还需要很多其他方面的技能。最近,来自美国求职公司Indeed的一份报告显示:在全美工作技能需求中,Linux/Shell技能仅次于SQL、Java、P...

使用Flask应用框架在Centos7.8系统上部署机器学习模型

安装centos7.8虚拟环境1、镜像链接...

shell编程

简介:Shell是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言。...

14天shell脚本入门学习-第二天#脚本和参数#排版修正

脚本是一种包含一系列命令的文本文件,通常用于自动化任务。Shell脚本是用Shell命令编写的脚本,可以在命令行中执行。掌握脚本的基础知识和变量的使用是编写高效脚本的关键。...

嵌入式Linux开发教程:Linux Shell

本章重点介绍Linux的常用操作和命令。在介绍命令之前,先对Linux的Shell进行了简单介绍,然后按照大多数用户的使用习惯,对各种操作和相关命令进行了分类介绍。对相关命令的介绍都力求通俗易懂,都给...

实现SHELL中的列表和字典效果

大家好,我是博哥爱运维。编写代码,很多情况下我们需要有种类型来存储数据,在python中有列表和字典,golang中有切片slice和map,那么在shell中,我们能否实现列表和字典呢,答案是肯定的...

14天shell脚本入门学习-第二天#脚本和变量

脚本是一种包含一系列命令的文本文件,通常用于自动化任务。Shell脚本是用Shell命令编写的脚本,可以在命令行中执行。掌握脚本的基础知识和变量的使用是编写高效脚本的关键。...

shell常用命令之awk用法介绍

一、awk介绍awk的强大之处,在于能生成强大的格式化报告。数据可以来自标准输入,一个或多个文件,或者其他命令的输出。他支持用户自定义函数和动态正则表达式等先进功能,是Linux/unix一个强大的文...

Linux编程Shell之入门——Shell数组拼接与合并

在Shell中,可以使用不同的方式实现数组拼接和合并。数组拼接指将两个数组中的元素合并成一个数组,而数组合并指将两个数组逐个组合成一个新数组。以下是关于Shell数组拼接和合并的详细介绍:数...

shell中如何逆序打印数组的内容,或者反转一个数组?

章节索引图首先请注意,有序的概念仅适用于索引数组,而不适用于关联数组。如果没有稀疏数组,答案会更简单,但是Bash的数组可以是稀疏的(非连续索引)。因此,我们需要引入一个额外的步骤。...

如何学好大数据开发?---shell基本语法

昨天我们初步了解到了shell的一些基本知识,比如shell的分类,常用的shell类型。今天就带来大数据开发之shell基本语法,掌握好基础才是最重要的,那接下来就开始学习shell的基本语法。一、...

Linux编程Shell之入门——Shell关联数组

关联数组是Shell中一种特殊的数组类型,它使用字符串作为下标。在关联数组中,每个元素都被标识为一个唯一的字符串键值,也称为关联数组的索引。在Shell中,可以使用declare或typeset命令...

从编译器视角看数组和指针

虽然有单独的文章描述数组和指针,但二者的关系实在值得再写一篇文章。...

取消回复欢迎 发表评论: