C语言学习笔记 —— 转换函数

一、字符串与数值互转

1.1 字符串转数值

1.1.1 字符串转整型

atoi


头文件:#include<stdlib.h>

功能把字符串转换成整型数(忽略掉字符串左空格,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(‘\0’)才结束转换)
函数定义int atoi(const char *nptr)
参数nptr:指向要转换的字符串
返回返回转换后的整数值

用法:

#include <stdlib.h>
#include <stdio.h>
 
int main(void)
{
    int n;
    char *str = "12345.67";
    n = atoi(str);
    printf("n=%d\n",n);
    return 0;
}

输出:n = 12345

sscanf

1.1.2 字符串转长整型

atol


头文件:#include<stdlib.h>

功能把字符串转换成长整型数(忽略掉字符串左空格,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(‘\0’)才结束转换)
函数定义long atol(const char *nptr)
参数nptr:指向要转换的字符串()
返回返回转换后的长整数值

用法:

#include <stdlib.h>
#include <stdio.h>
 
int main(void)
{
    long l;
    char *str = "98765432";
    l = atol(str); /* 原来为l = atol(str); */
    printf("l = %ld\n", l);
    return(0);
}

输出:l = 98765432

strtol

sscanf(val_in,%04x%04x%04x”, &val_out[0], &val_out[1], &val_out[2])

for (k = 0 ;k < 48 ; k++)
{
	sscanf(&val_in[k*2], "%02x", &val_out[k]);    // 字符串格式化输到字符数组   
}

头文件:#include<stdlib.h>

功能把字符串字符串根据参数base来转换成长整型数
函数定义long int strtol(const char *nptr,char **endptr,int base)
参数nptr:指向要转换的字符串
endptr:指向停止转换的位置,若字符串nptr的所有字符都成功转换成数字则endptr指向串结束符’\0’
base:采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制等。当base值为0时则是采用10进制做转换,但遇到如’0x’前置字符则会使用16进制做转换、遇到’0’前置字符而不是’0x’的时候会使用8进制做转换
返回返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中

特点:

  • 不仅可以识别十进制整数,还可以识别其它进制的整数,取决于base参数,比如
    strtol("0XDEADbeE~~", NULL, 16)返回0xdeadbee的值,
    strtol("0777~~", NULL, 8)返回0777的值。

  • endptr是一个传出参数,函数返回时指向后面未被识别的第一个字符
    例如char *pos; strtol("123abc", &pos, 10);,strtol返回123,pos指向字符串中的字母a。
    如果字符串开头没有可识别的整数,
    例如char *pos; strtol("ABCabc", &pos, 10);,则strtol返回0,pos指向字符串开头,可以据此判断这种出错的情况,而这是atoi处理不了的。

  • 如果字符串中的整数值超出long int的表示范围(上溢或下溢),则strtol返回它所能表示的最大(或最小)整数,并设置errno为ERANGE
    例如strtol("0XDEADbeef~~", NULL, 16)返回0x7fffffff并设置errno为ERANGE

用法:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    char *string, *stopstring;
    int base;
    long l;
    string = "-1011 This stopped it";
    l = strtol(string, &stopstring, 10);
    printf("string = %s\n", string);
    printf("strtol = %ld\n", l);
    printf("Stopped scan at: %s\n", stopstring);
    return 0;
}

输出:
string = -1011 This stopped it
strtol = -1011
Stopped scan at:  This stopped it

1.1.3 字符串转无符号长整型

strtoul


头文件:#include<stdlib.h>

功能把字符串字符串根据参数base来转换成无符号的长整型数
函数定义unsigned long strtoul(const char *nptr,char **endptr,int base)
参数nptr:指向要转换的字符串
endptr:指向停止转换的位置,若字符串nptr的所有字符都成功转换成数字则endptr指向串结束符’\0’
base:采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制等。当base值为0时则是采用10进制做转换,但遇到如’0x’前置字符则会使用16进制做转换、遇到’0’前置字符而不是’0x’的时候会使用8进制做转换
返回返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中

特点:
同上面strtol函数。

用法:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    int a;
    char pNum[]="0xFF";
    a=strtoul(pNum,0,0);//最后的0,表示自动识别pNum是几进制
    printf("%ul\n",a);
    return 0;
}

输出:255

1.1.4 字符串转浮点型

atof


头文件:#include<stdlib.h>

功能把字符串转换成浮点数(忽略掉字符串左空格,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时(‘\0’)才结束转换)
函数定义double atof(const char *nptr)
参数nptr:指向要转换的字符串(可包含正负号、小数点或E(e)来表示指数部分)
返回返回转换后的浮点型数

用法:

#include <stdlib.h>
#include <stdio.h>
 
int main(void)
{
    char *a = "-100.23";
    char *b = "200e-2";
    double c;
    c = atof(a)+atof(b);
    printf(“c = %.2lf\n”,c);
    return 0;
}

输出:c = -98.23

strtod


头文件:#include<stdlib.h>

功能把字符串转换成浮点数
函数定义double strtod(const char *nptr,char **endptr)
参数nptr:指向要转换的字符串(可包含正负号、小数点或E(e)来表示指数部分)
endptr:指向停止转换的位置,若字符串nptr的所有字符都成功转换成数字则endptr指向串结束符’\0
返回返回转换后的浮点型数

用法:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    char *endptr;
    char a[] = "12345.6789";
    char b[] = "1234.567qwer";
    char c[] = "-232.23e4";
    printf( "a = %lf\n", strtod(a,NULL) );
    printf( "b = %lf\n", strtod(b,&endptr) );
    printf( "endptr = %s\n", endptr );
    printf( "c = %lf\n", strtod(c,NULL) );
    return 0;
}

输出:
a = 12345.678900
b = 1234.567000
endptr = qwer
c = -2322300.000000

1.2 数值转字符串

1.2.1 整型转字符串

sprintf


头文件:#include<stdio.h>

功能把格式化的数据写入某个字符串中,结尾自动追加'\0'字符
函数定义int sprintf(char *string, char *format [,argument,…])
参数string:这是指向一个字符数组的指针,该数组存储了 C 字符串
format:这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是%[flags][width][.precision][length]specifier
[argument]…:根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同
返回如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符‘\0’。如果失败,则返回一个负数。即,如果“Hello”被写入空间足够大的string后,函数sprintf 返回5。

注意:
使用sprintf对于写入buffer的字符数是没有限制的,这就存在了缓冲区溢出的可能性。解决这个问题,尽量使用”%.ns”的形式指定最大字符数。或者可以考虑使用snprintf函数,该函数可对写入字符数做出限制。

用法:

#include <stdio.h> 
 
int main(void)
{
    char buffer[200];
    int i = 35;
    sprintf(buffer, "%d\n", i);
    printf("integer = %d string = %s\n", i, buffer);
    return 0;
}

输出:
integer = 35 string = 35

itoa


头文件:#include<stdlib.h>#include<cstdlib.h>

功能把整型数转换成字符串
函数定义char *itoa(int value, char *str, int base)
参数value:被转换的整数
str:转换后储存的字符数组
base:转换进制数,如2,8,10,16进制等,大小应在2-36之间
返回返回指向str的指针

注意:
itoa并是一个非标准的C/C++函数,它是Windows持有的,如果要写跨平台的程序,请用sprintf

用法:

#include <stdlib.h> 
//#include <cstdlib>
#include <stdio.h> 
//#include <cstdio>
 
int main(void)
{
    int number=12345;
    char string[25];
    itoa(number, string, 10);//按10进制转换
    printf("integer = %d string = %s\n", number, string);
    itoa(number, string, 16);//按16进制转换
    printf("integer = %d string = %s\n", number, string);
    return 0;
}

输出:
integer = 12345 string = 12345 ——说明12345的十进制表示就是12345
integer = 12345 string = 3039 ——说明12345的十六进制表示是0x3039

1.2.2 长整型转字符串

sprintf


用法同上

ltoa


用法同上

1.2.3 无符号长整型转字符串

sprintf


用法同上

ultoa


用法同上

1.2.4 浮点型转字符串

sprintf


用法同上

gcvt


头文件:#include<stdlib.h>

功能把浮点型数转换为字符串,取四舍五入
函数定义char *gcvt(double value, int ndigit, char *buf)
参数value:被转换的浮点数
ndigit:存储的有效数字位数
buf:转换后储存的字符数组
返回返回一个指向结果的存储位置的指针

注意:
如果一个缓冲区的尺寸为digits的尺寸+1,该函数覆盖该缓冲区的末尾。这是因为转换的字符串包括一个小数点以及可能包含符号和指数信息。不提供上溢出。gcvt试图以十进制格式产生digits数字,如果不可能,它以指数格式产生digits数字,在转换时可能截除尾部的0。

用法:

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    char str[25];
    double num;
    int sig = 5; /* significant digits */
    /* a regular number */
    num = 9.876;
    gcvt(num, sig, str);
     
    printf("string = %s\n", str);
    /* a negative number */
    num = -123.4567;
    gcvt(num, sig, str);
     
    printf("string = %s\n", str);
    /* scientific notation */
    num = 0.678e5;
    gcvt(num, sig, str);
     
    printf("string = %s\n", str);
    return(0);
}

输出:
string = 9.876
string = -123.46
string = 67800

ecvt


头文件:#include<stdlib.h>

功能双精度浮点型数转换为字符串,转换结果中不包括十进制小数点
函数定义char* ecvt(double value, int ndigit, int *decpt, int *sign)
参数value:待转换的双精度浮点数
ndigit:存储的有效数字位数
decpt:存储的小数点位置
sign:转换的数的符号,0为正数,1为负数
返回指向生成的字符串

注意:
这个函数存储最多ndigit个数字值作为一个字符串,并添加一个空数字符(‘\0’),如果value中的数字个数超过ndigit,低位数字被舍入。如果少于ndigit个数字,该字符串用0填充。只有数字才存储在该字符串中,小数点位置和value符号在调用之后从decpt和sign获取。decpt参数指出给出小数点位置的整数值, 它是从该字符串的开头位置计算的。0或负数指出小数点在第一个数字的左边。sign参数指出一个指出转换的数的符号的整数。如果该整数为0,这个数为正数,否则为负数。

请尽量使用sprintf函数做转换。

用法:

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    char *string;
    double value;
    int dec,sign;
    int ndig = 10;

    value = 9.876;
    string = ecvt(value, ndig, &dec, &sign);
    printf("string=%s dec=%d sign=%d\n", string, dec, sign);

    value = -123.45;
    ndig = 15;
    string = ecvt(value, ndig, &dec, &sign);
    printf("string=%s dec=%d sign=%d\n", string, dec, sign);

    value = 0.6789e5;/*scientificnotation*/
    ndig = 5;
    string = ecvt(value, ndig, &dec, &sign);
    printf("string=%s dec=%d sign=%d\n", string, dec, sign);

    return 0;
}

输出:
string=9876000000 dec=1 sign=0
string=123450000000000 dec=3 sign=1
string=67890 dec=5 sign=0

fcvt


指定位数为转换精度,其余同ecvt()

二、字节流与数值互转

2.1 字节流转数值

2.1.1 字节流转无符号整型32位

U8ToU32


头文件:#include <stdint.h>

实现:

#include <stdint.h>

/**
 @brief uint8_t转换为uint32_t
 @param pHexArr -[in] 十六进制数组
 @return 无符号整型数值
*/
uint32_t U8ToU32(uint8_t *pHexArr)
{
    return (uint32_t)((pHexArr[0] << 24) + (pHexArr[1] << 16) + (pHexArr[2] << 8) + pHexArr[3]);
}

用法:

#include <stdio.h>
#include <stdint.h>

int main()
{
    uint8_t arr[4] = {0x01, 0x02, 0x03, 0x04};
    uint32_t i = U8ToU32(arr);
    printf("hex:0x%x dec:%d\n", i, i);

    return(0);
}

输出:hex:0x1020304 dec:16909060

2.1.2 字节流转无符号整型16位

U8ToU16


头文件:#include <stdint.h>

实现:

#include <stdint.h>

/**
 @brief uint8_t转换为uint16_t
 @param pHexArr -[in] 十六进制数组
 @return 无符号整型数值
*/
uint16_t U8ToU16(uint8_t *pHexArr)
{
    return (uint16_t)((pHexArr[0] << 8) + pHexArr[1]);
}

用法:

#include <stdio.h>
#include <stdint.h>

int main()
{
    uint8_t arr[2] = {0x01, 0x02};
    uint16_t i = U8ToU16(arr);
    printf("hex:0x%x dec:%d\n", i, i);

    return(0);
}

输出:hex:0x102 dec:258

2.2.1 无符号整型32位转字节流

U32ToU8


头文件:#include <stdint.h>

实现:

#include <stdint.h>

/**
 @brief uint32_t转换为uint8_t
 @param value -[in] 无符号整型数值
 @param pHexArr -[out] 十六进制数组
 @return 无
*/
void U32ToU8(uint32_t value, uint8_t *pHexArr)
{
    *(pHexArr + 3) = (uint8_t)(0xFF & value);
    *(pHexArr + 2) = (uint8_t)((0xFF00 & value) >> 8);
    *(pHexArr + 1) = (uint8_t)((0xFF0000 & value) >> 16);
    *(pHexArr) = (uint8_t)((0xFF000000 & value) >> 24);
}

用法:

#include <stdio.h>
#include <stdint.h>

int main()
{
    uint8_t arr[4];
    uint32_t i = 0x11223344;
    U32ToU8(i, arr);
    printf("%02x %02x %02x %02x\n", arr[0], arr[1], arr[2], arr[3]);
    
    return(0);
}

输出:11 22 33 44

2.2.2 无符号整型16位转字节流

U16ToU8


头文件:#include <stdint.h>

实现:

#include <stdint.h>

/**
 @brief uint16_t转换为uint8_t
 @param value -[in] 无符号整型数值
 @param pHexArr -[out] 十六进制数组
 @return 无
*/
void U16ToU8(uint16_t value, uint8_t *pHexArr)
{
    *(pHexArr + 1) = (uint8_t)(0xFF & value);
    *(pHexArr) = (uint8_t)((0xFF00 & value) >> 8);
}

用法:

#include <stdio.h>
#include <stdint.h>

int main()
{
    uint8_t arr[2];
    uint16_t i = 0x1122;
    U16ToU8(i, arr);
    printf("%02x %02x\n", arr[0], arr[1]);
    
    return(0);
}

输出:11 22

三、字符串与字节流互转

3.1 十六进制字符串转换为字节流

HexStrToBytes


头文件:#include <stdint.h>#include <ctype.h>

实现:

#include <stdint.h>
#include <ctype.h>

/**
 @brief 十六进制字符串转换为字节流
 @param pHexStr -[in] 十六进制字符串
 @param hexStrLen -[in] 字符串长度
 @param pHexArr -[out] 十六进制数组
 @return 无
*/
void HexStrToBytes(const char *pHexStr, uint16_t hexStrLen, uint8_t *pHexArr)
{
    uint16_t i;
    uint8_t highByte, lowByte;
      
    for(i = 0; i < hexStrLen; i += 2)
    {  
        highByte = toupper(pHexStr[i]);    // toupper转换为大写字母
        lowByte = toupper(pHexStr[i + 1]);

        if(highByte > 0x39)
        {            
            highByte -= 0x37;
        }            
        else
        {            
            highByte -= 0x30;
        }

        if(lowByte > 0x39)
        {            
            lowByte -= 0x37;
        }
        else
        {            
            lowByte -= 0x30;
        }

        pHexArr[i / 2] = (highByte << 4) | lowByte;
    }
}

用法:

#include <stdio.h>
#include <stdint.h>
#include <ctype.h>
#include <string.h>

int main(void)
{
    uint8_t hex[5];
    char string[20] = "a1b2c3e4f5";
    HexStrToBytes(string, strlen(string), hex);
    printf("%x %x %x %x %x\n", hex[0], hex[1], hex[2], hex[3], hex[4]);

    return 0;
}

输出:a1 b2 c3 e4 f5

3.2 字节流转十六进制字符串

BytesToHexStr


头文件:#include <stdint.h>

  • 实现一:
#include <stdint.h>

/**
 @brief 字节流转十六进制字符串
 @param pHexArr -[in] 十六进制数组
 @param hexArrLen -[in] 数组长度
 @param pHexStr -[out] 十六进制字符串
 @return 无
*/
void BytesToHexStr(const uint8_t *pHexArr, uint16_t hexArrLen, char *pHexStr)
{
    uint16_t i;
    char low, high;

    for(i = 0; i < hexArrLen; i++)
    {
        high = 48 + pHexArr[i] / 16;
        low = 48 + pHexArr[i] % 16;
        if(high > 57) 
        {
            high += 7;
        }
        if(low > 57) 
        {
            low += 7;
        }
        pHexStr[i * 2] = high;
        pHexStr[i * 2 + 1] = low;
    }
    pHexStr[hexArrLen * 2] = '\0';
}
  • 实现二:
#include <stdint.h>

/**
 @brief 字节流转十六进制字符串
 @param pHexArr -[in] 十六进制数组
 @param hexArrLen -[in] 数组长度
 @param pHexStr -[out] 十六进制字符串
 @return 无
*/
void BytesToHexStr(const uint8_t *pHexArr, uint16_t hexArrLen, char *pHexStr)
{
    uint16_t i;

    for(i = 0; i < hexArrLen; i++)
    {
        sprintf((char *)pHexStr + i * 2, "%02x", *(pHexArr + i));
    }
    *(pHexStr + i * 2) = '\0';
}

用法:

#include <stdio.h>
#include <stdint.h>

int main(void)
{
    uint8_t hex[4] = {0x01, 0x02, 0x03, 0x04};
    char string[9];
    BytesToHexStr(hex, 4, string);
    printf("%s\n", string);
    
    return 0;
}

输出:01020304

四、大小端互转

4.1 大小端概念

大端模式: 是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中(高存低,低存高)
小端模式: 是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中(高存高,低存低)

假如32位宽(uint32_t)的数据0x12345678,从地址0x08004000开始存放:

地址大端存放内容小端存放内容
0x080040030x780x12
0x080040020x560x34
0x080040010x340x56
0x080040000x120x78

常见CPU的字节序:

  • 大端模式:PowerPC、IBM、Sun
  • 小端模式:x86、DEC
  • ARM既可以工作在大端模式,也可以工作在小端模式。STM32属于小端模式

大小端应用的地方很多,如通信协议、数据存储等。如果字节序不一致,就需要转换。

网络字节顺序NBO(Network Byte Order):
按从高到低的顺序存储,在网络上使用同一的网络字节顺序,可避免兼容性问题(大端模式

主机字节顺序HBO(Host Byte Order):
不同的机器HBO不相同,与CPU的设计有关,数据的顺序是由CPU决定的,而与操作系统无关

4.2 大端转小端

4.2.1 无符号整型32位大端转小端

U32SwapEndian


头文件:#include <stdint.h>

实现:

#include <stdint.h>

#define U32SwapEndian(x) \
    (uint32_t)((((uint32_t)(x) & 0xff000000) >> 24) | \
                (((uint32_t)(x) & 0x00ff0000) >> 8) | \
                (((uint32_t)(x) & 0x0000ff00) << 8) | \
                (((uint32_t)(x) & 0x000000ff) << 24) \
             ) 

用法:

#include <stdio.h>
#include <stdint.h>
             
int main(void)
{
    uint32_t i = 0x12345678;
    i = U32SwapEndian(i);
    printf("%x\n", i);

    return 0;
}

输出:78563412

ntohl


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <winsock.h>
功能将一个32位数从网络字节顺序转换成主机字节顺序
函数定义uint32_t ntohl(uint32_t netlong)
参数netlong:网络字节顺序表达的32位数
返回返回一个主机字节顺序的值

用法:

#include <stdio.h>
#include <arpa/inet.h>
// #include <winsock.h>
             
int main(void)
{
    uint32_t i = 0x12345678;
    i = ntohl(i);
    printf("%x\n", i);

    return 0;
}

输出:78563412

4.2.2 无符号整型16位大端转小端

U16SwapEndian


头文件:#include <stdint.h>

实现:

#include <stdint.h>

#define U16SwapEndian(x) \
    (uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
                (((uint16_t)(x) & 0xff00) >> 8) \
             ) 

用法:

#include <stdio.h>
#include <stdint.h>
             
int main(void)
{
    uint16_t i = 0x1234;
    i = U16SwapEndian(i);
    printf("%x\n", i);

    return 0;
}

输出:3412

ntols


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <winsock.h>
功能将一个16位数从网络字节顺序转换成主机字节顺序
函数定义uint16_t ntohs(uint16_t netshort)
参数netshort:网络字节顺序表达的16位数
返回返回一个主机字节顺序的值

用法:
ntohl

4.3 小端转大端

4.3.1 无符号整型32位小端转大端

U32SwapEndian


同上4.2.1

htonl


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <winsock.h>
功能将一个32位数从主机字节顺序转换成网络字节顺序
函数定义uint32_t htonl(uint32_t hostlong)
参数hostlong:主机字节顺序表达的32位数
返回返回一个网络字节顺序的值

用法:
ntohl

4.3.2 无符号整型16位小端转大端

U16SwapEndian


同上4.2.1

htons


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <winsock.h>
功能将一个16位数从主机字节顺序转换成网络字节顺序
函数定义uint16_t htonl(uint16_t hostshort)
参数hostshort:主机字节顺序表达的16位数
返回返回一个网络字节顺序的值

用法:
ntohl

五、IP地址格式互转

5.1 点分十进制字符串转网络字节序

inet_aton


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <WINSOCK2.h>
功能将一个16位数从主机字节顺序转换成网络字节顺序,用途多于IPv4的IP转化
函数定义int inet_aton(const char *string, struct in_addr *addr)
参数string:IPv4点分十进制字符串,例如“192.168.1.2”、“10.28.1.1”等
addr:点分十进制转换成二进制后的结构体(网络字节序)
返回返回非0表示cp主机有地有效,返回0表示主机地址无效

用法:

#include <stdio.h>
#include <arpa/inet.h>

int main(void)
{
    char *string="192.168.1.2";
    struct in_addr ip={0};
    unsigned char *c=NULL;
    int integer=0xc0a80102;/*用来对比测试*/

    if(!inet_aton(string, &ip))
    {
        printf("%s:%d error\n", __func__, __LINE__);
        return -1;
    }
    printf("%8.8x ---- %u\n", ip.s_addr, ip.s_addr);/**/
    c=(char *)&ip.s_addr;
    printf("%2.2x ---- %2.2x --- %2.2x --- %2.2x\n", *c, *(c+1), *(c+2), *(c+3));

    printf("%8.8x ---- %u\n", integer, integer);/**/
    c=(char *)&integer;
    printf("%2.2x ---- %2.2x --- %2.2x --- %2.2x\n", *c, *(c+1), *(c+2), *(c+3));

    return 0;
}

输出:
0201a8c0 ---- 33663168			
c0 ---- a8 --- 01 --- 02		--->inet_aton()转换后的字节序

c0a80102 ---- 3232235778
02 ---- 01 --- a8 --- c0		--->正常的主机字节序

inet_pton


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <WS2tcpip.h>
功能将点分文本的IP地址转换为二进制网络字节序的IP地址。而且能够处理IPv4IPv6
函数定义int inet_pton(int af, const char *src, void *dst)
参数af:必须是 AF_INET 或 AF_INET6,AF_INET 表示待转换的 IPv4地址,AF_INET6 表示待转换的是 IPv6 地址
src:指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的),函数将该地址转换为in_addr的结构体,并复制在*dst中。
dst:接收转换后的数据
返回如果函数出错将返回一个负值,并将errno设置为EAFNOSUPPORT,如果参数af指定的地址族和src格式不对,函数将返回0

用法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main (void)
{

    char IPdotdec[20] = "192.168.1.1"; //存放点分十进制IP地址
    struct in_addr s; // IPv4地址结构体

    inet_pton(AF_INET, IPdotdec, (void *)&s);
    printf("inet_pton: 0x%x\n", s.s_addr); // 注意得到的字节序

    // 反转换
    inet_ntop(AF_INET, (void *)&s, IPdotdec, 16);
    printf("inet_ntop: %s\n", IPdotdec);
}

输出:
inet_pton: 0x101a8c0
inet_ntop: 192.168.1.1

inet_addr


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <Winsock2.h>
功能将一个点分十进制的IP转换成一个长整型数(u_long类型),用途多于IPv4的IP转化
函数定义in_addr_t inet_addr(const char* strptr)
参数strptr:指向字符型的地址,即ASCII的地址的首地址(ddd.ddd.ddd.ddd格式的)
返回若字符串有效则将字符串转换为32位二进制网络字节序的IPV4地址,否则为INADDR_NONE

用法:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

int main(void)
{
    char IPdotdec[20];
    unsigned long ip;
    ip = inet_addr("192.168.1.1");
    // 反转换
    inet_ntop(AF_INET, (void *)&ip, IPdotdec, 16);
    printf("0x%x\n", ip);
    printf("%s\n", IPdotdec);

    return 0;
}

输出:
inet_pton: 0x101a8c0
inet_ntop: 192.168.1.1

5.2 网络字节序转点分十进制字符串

inet_ntoa


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <WINSOCK2.h>
功能将一个网络字节顺序转换成16位数从主机字节顺序,用途多于IPv4的IP转化
函数定义char *inet_ntoa(struct in_addr in)
参数in:点分十进制转换成二进制后的结构体(网络字节序)
返回IPv4点分十进制字符串指针,例如“192.168.1.2”、“10.28.1.1”等

注意:
不可重入! 因为转换后的字符串使用同一块静态内存区,再次调用会被覆盖。

用法:

#include <stdio.h>
#include <arpa/inet.h>

int main(void)
{
    char *string = NULL;
    struct in_addr ip;
    unsigned char *c = NULL;

    ip.s_addr = 0xc0a80102;

    if(!(string = inet_ntoa(ip)))
    {
        return -1;
    }
    printf("%s\n", string);
    printf("%8.8x ---- %u\n", ip.s_addr, ip.s_addr);
    c = (char *)&ip.s_addr;
    printf("%2.2x ---- %2.2x --- %2.2x --- %2.2x\n", *c, *(c+1), *(c+2), *(c+3));


    ip.s_addr = htonl(0xc0a80102);/*转换为网络字节序*/
    if(!(string = inet_ntoa(ip)))
    {
        return -1;
    }
    printf("%s\n", string);
    printf("%8.8x ---- %u\n", ip.s_addr, ip.s_addr);/**/
    c = (char *)&ip.s_addr;
    printf("%2.2x ---- %2.2x --- %2.2x --- %2.2x\n", *c, *(c+1), *(c+2), *(c+3));

    return 0;
}

输出:
2.1.168.192
c0a80102 ---- 3232235778
02 ---- 01 --- a8 --- c0
192.168.1.2
0201a8c0 ---- 33663168
c0 ---- a8 --- 01 --- 02

inet_ntop


头文件:

  • Linux下 #include <arpa/inet.h>
  • Windows下 #include <WS2tcpip.h>
功能将二进制网络字节序的IP地址转换为点分文本的IP地址。而且能够处理IPv4IPv6
函数定义const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
参数af:必须是 AF_INET 或 AF_INET6,AF_INET 表示待转换的 IPv4地址,AF_INET6 表示待转换的是 IPv6 地址
src:指向的二进制 IP 地址转换为点分十进制形式的字符串,并将字符串存放在参数 dts所指的缓冲区中
size:指定了该缓冲区的大小
返回成功时会返回 dst 指针。如果 size 的值太小了,那么将会返回 NULL 并将 errno 设置为 ENOSPC

用法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main (void)
{

    char IPdotdec[20] = "192.168.1.1"; //存放点分十进制IP地址
    struct in_addr s; // IPv4地址结构体

    inet_pton(AF_INET, IPdotdec, (void *)&s);
    printf("inet_pton: 0x%x\n", s.s_addr); // 注意得到的字节序

    // 反转换
    inet_ntop(AF_INET, (void *)&s, IPdotdec, 16);
    printf("inet_ntop: %s\n", IPdotdec);
}

输出:
inet_pton: 0x101a8c0
inet_ntop: 192.168.1.1

六、十六进制负数原码转十进制数

#include <stdio.h>
#include <stdint.h>

int8_t NegativeHexToDec(uint8_t hex)
{
	int8_t dec;
    if(hex > 128)
	{
		dec = 0 - hex - 128;
	}
	else
	{
		dec = hex;
	}
	return dec;
}

uint8_t DecToNegativeHex(int8_t dec)
{
	uint8_t hex;
    if(dec < 0)
	{
		hex = 0 - dec - 128;
	}
	else
	{
		hex = dec;
	}
	return hex;
}

int main()
{
   uint8_t a = DecToNegativeHex(-10);
   printf("%02x\n", a);
   int8_t b = NegativeHexToDec(0x8a);
   printf("%d\n", b);
   
   return 0;
}

输出:8a
输出:-10

七、精度转换

val_out = val_in/1000*255+0.5 //精度的转换,1000精度转到255

• 由 Leung 写于 2022 年 8 月 14 日

• 参考:大小端、字节顺序转换函数和IP地址格式转换函数
    inet_aton和inet_ntoa