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


    一、字符串与数值互转

    1.1 字符串转数值

    1.1.1 字符串转整型

    atoi


    头文件:#include

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

    用法:

    #include 
    #include 
     
    int main(void)
    {
        int n;
        char *str = "12345.67";
        n = atoi(str);
        printf("n=%d\n",n);
        return 0;
    }
    
    输出:n = 12345
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1.1.2 字符串转长整型

    atol


    头文件:#include

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

    用法:

    #include 
    #include 
     
    int main(void)
    {
        long l;
        char *str = "98765432";
        l = atol(str); /* 原来为l = atol(str); */
        printf("l = %ld\n", l);
        return(0);
    }
    
    输出:l = 98765432
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    strtol


    头文件:#include

    功能把字符串字符串根据参数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 
    #include 
    
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1.1.3 字符串转无符号长整型

    strtoul


    头文件:#include

    功能把字符串字符串根据参数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 
    #include 
    
    int main()
    {
        int a;
        char pNum[]="0xFF";
        a=strtoul(pNum,0,0);//最后的0,表示自动识别pNum是几进制
        printf("%ul\n",a);
        return 0;
    }
    
    输出:255
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1.1.4 字符串转浮点型

    atof


    头文件:#include

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

    用法:

    #include 
    #include 
     
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    strtod


    头文件:#include

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

    用法:

    #include 
    #include 
    
    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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    1.2 数值转字符串

    1.2.1 整型转字符串

    sprintf


    头文件:#include

    功能把格式化的数据写入某个字符串中,结尾自动追加'\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  
     
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    itoa


    头文件:#include#include

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

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

    用法:

    #include  
    //#include 
    #include  
    //#include 
     
    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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1.2.2 长整型转字符串

    sprintf


    用法同上

    ltoa


    用法同上

    1.2.3 无符号长整型转字符串

    sprintf


    用法同上

    ultoa


    用法同上

    1.2.4 浮点型转字符串

    sprintf


    用法同上

    gcvt


    头文件:#include

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

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

    用法:

    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    ecvt


    头文件:#include

    功能双精度浮点型数转换为字符串,转换结果中不包括十进制小数点
    函数定义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 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    fcvt


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

    二、字节流与数值互转

    2.1 字节流转数值

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

    U8ToU32


    头文件:#include

    实现:

    #include 
    
    /**
     @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]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    用法:

    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    U8ToU16


    头文件:#include

    实现:

    #include 
    
    /**
     @brief uint8_t转换为uint16_t
     @param pHexArr -[in] 十六进制数组
     @return 无符号整型数值
    */
    uint16_t U8ToU16(uint8_t *pHexArr)
    {
        return (uint16_t)((pHexArr[0] << 8) + pHexArr[1]);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    用法:

    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

    U32ToU8


    头文件:#include

    实现:

    #include 
    
    /**
     @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    用法:

    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

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

    U16ToU8


    头文件:#include

    实现:

    #include 
    
    /**
     @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    用法:

    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    三、字符串与字节流互转

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

    HexStrToBytes


    头文件:#include #include

    实现:

    #include 
    #include 
    
    /**
     @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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    用法:

    #include 
    #include 
    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    BytesToHexStr


    头文件:#include

    • 实现一:
    #include 
    
    /**
     @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';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 实现二:
    #include 
    
    /**
     @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';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    用法:

    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    四、大小端互转

    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

    实现:

    #include 
    
    #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) \
                 ) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    用法:

    #include 
    #include 
                 
    int main(void)
    {
        uint32_t i = 0x12345678;
        i = U32SwapEndian(i);
        printf("%x\n", i);
    
        return 0;
    }
    
    输出:78563412
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ntohl


    头文件:

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

    用法:

    #include 
    #include 
    // #include 
                 
    int main(void)
    {
        uint32_t i = 0x12345678;
        i = ntohl(i);
        printf("%x\n", i);
    
        return 0;
    }
    
    输出:78563412
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

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

    U16SwapEndian


    头文件:#include

    实现:

    #include 
    
    #define U16SwapEndian(x) \
        (uint16_t)((((uint16_t)(x) & 0x00ff) << 8) | \
                    (((uint16_t)(x) & 0xff00) >> 8) \
                 ) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    用法:

    #include 
    #include 
                 
    int main(void)
    {
        uint16_t i = 0x1234;
        i = U16SwapEndian(i);
        printf("%x\n", i);
    
        return 0;
    }
    
    输出:3412
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    ntols


    头文件:

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

    用法:
    ntohl

    4.3 小端转大端

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

    U32SwapEndian


    同上4.2.1

    htonl


    头文件:

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

    用法:
    ntohl

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

    U16SwapEndian


    同上4.2.1

    htons


    头文件:

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

    用法:
    ntohl

    五、IP地址格式互转

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

    inet_aton


    头文件:

    • Linux下 #include
    • Windows下 #include
    功能将一个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 
    #include 
    
    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		--->正常的主机字节序
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    inet_pton


    头文件:

    • Linux下 #include
    • Windows下 #include
    功能将点分文本的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 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    inet_addr


    头文件:

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

    用法:

    #include 
    #include 
    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

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

    inet_ntoa


    头文件:

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

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

    用法:

    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    inet_ntop


    头文件:

    • Linux下 #include
    • Windows下 #include
    功能将二进制网络字节序的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 
    #include 
    #include 
    #include 
    
    #include 
    #include 
    #include 
    
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    • 由 Leung 写于 2022 年 8 月 14 日

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

  • 相关阅读:
    Java SPI的原理和实践
    一个STC单片机电路的梳理和编程
    创建单例模式的方法
    微信小程序开发公司你懂得选择吗?
    西电通信技术基础实验
    计算机视觉结合深度学习项目-智能停车场空车位实时识别
    数据结构每日亿题(七)
    Springboot 多模块(A依赖B)集成mybatis , mybatis.mapper-locations 配置多个mapper路径配置
    【目标检测】Co-DETR:ATSS+Faster RCNN+DETR协作的先进检测器(ICCV 2023)
    解密网络通信的关键技术(下):DNS、ARP、DHCP和NAT,你了解多少?
  • 原文地址:https://blog.csdn.net/qq_36347513/article/details/126336791