现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

bsd socket网络通讯必备工具类:uint转byte

2013-08-08 23:11 工业·编程 ⁄ 共 6111字 ⁄ 字号 暂无评论

//
//  ConvertUtil.h
//  MinaCppClient
//
//  Created by yang3wei on 7/22/13.
//  Copyright (c) 2013 yang3wei. All rights reserved.
//

#ifndef __MinaCppClient__ConvertUtil__
#define __MinaCppClient__ConvertUtil__

#include <string>

/**
* htonl 表示 host to network long ,用于将主机 unsigned int 型数据转换成网络字节顺序;
* htons 表示 host to network short ,用于将主机 unsigned short 型数据转换成网络字节顺序;
* ntohl、ntohs 的功能分别与 htonl、htons 相反。
*/

/**
* byte 不是一种新类型,在 C++ 中 byte 被定义的是 unsigned char 类型;
* 但在 C# 里面 byte 被定义的是 unsigned int 类型
*/
#ifndef TYPE_BYTE
#define TYPE_BYTE
typedef unsigned char byte;
#endif

#ifndef TYPE_UINT
#define TYPE_UINT
typedef unsigned int uint;
#endif

using namespace std;

#pragma mark int2bytes() & bytes2int()

/**
* 功能:uint 转 byte
* 心得:方法无返回的优点:做内存管理清爽整洁。
* 1.如果返回值为 int,float,long,double 等简单类型,直接返回即可;
* 2.如果返回值为分配在栈上的数组或对象,亦可直接返回;
* 3.如果返回值是分配在堆内存上的数组或对象,最好不要放在返回值里返回,做成出参的效果会比较好。
* 在 OpenGL 中此种设计模式比较常见
* 业界规范:出参在前,入参在后
*/
void uint2bytes(byte* out_pArrBytes, uint in_uiValue);

/**
* 功能:byte 转 uint
*/
uint bytes2uint(byte* in_pArrBytes);

#pragma mark hexStr2bytes() & bytes2hexStr()

/**
* 功能:char 转 int
* 返回:转换出来的 int
*/
// int hexChar2int(char c);

/**
* 功能:十六进制字符串转字节数组
* 返回:转换出来的字节数组的长度
* 注意:
*/
//int hexStr2bytes(std::string in_oStrHex, byte* out_pArrBytes);
void hexStr2bytes(byte* out_pArrBytes, int in_iArrSize, const char* in_pArrCharHex);

/**
* 功能:字节数组转十六进制字符串
* 返回:转换出来的十六进制字符串
*/
//std::string bytes2hexStr(byte* in_pArrBytes, int in_iSize);
void bytes2hexStr(string& out_oStrHex, byte* in_pArrBytes, int in_iArrSize);

#endif /* defined(__MinaCppClient__ConvertUtil__) */

//
//  ConvertUtil.cpp
//  MinaCppClient
//
//  Created by yang3wei on 7/22/13.
//  Copyright (c) 2013 yang3wei. All rights reserved.
//

#include "ConvertUtil.h"

#define HEX_ELEMENTS    "0123456789ABCDEF"

/**
* 1.传参规范:
* 一般是输出 dest 在前面,输入 source 在后面。
*(库函数,一般都是输出在前面,输入在后面。例如字符串拷贝函数,strcpy)
* 2.此方法无必要做清零处理
* 譬如说 1111 0000 ,现在赋了一个值 0000 0001,不清零的话不会出现 1111 0001 这种情况
* 3.检查指针是否为 NULL,是个好习惯
*/
void uint2bytes(byte* out_pArrBytes, uint in_uiValue)
{
    if (!out_pArrBytes)
    {
        printf("空指针!\n");
        return;
    }
   
    out_pArrBytes[0] = (byte)(in_uiValue & 0xff);
    out_pArrBytes[1] = (byte)((in_uiValue >> 8) & 0xff);
    out_pArrBytes[2] = (byte)((in_uiValue >> 16) & 0xff);
    out_pArrBytes[3] = (byte)((in_uiValue >> 24) & 0xff);
}

uint bytes2uint(byte* in_pArrBytes)
{
    if (!in_pArrBytes)
    {
        printf("空指针!\n");
        return 0;
    }
   
    uint t_uiRetVal = (uint)in_pArrBytes[0] & 0xff;
    t_uiRetVal |= (((uint)in_pArrBytes[1] << 8) & 0xff00);
    t_uiRetVal |= (((uint)in_pArrBytes[2] << 16) & 0xff0000);
    t_uiRetVal |= (((uint)in_pArrBytes[3] << 24) & 0xff000000);
    return t_uiRetVal;
}

/**
* 这个函数最大的问题,就是用了很多 if 判断语句,
* 运气不好的时候(执行到最后一行 return 0; 的时候),要比较 6 次,跳转 3次
* (每次 if 里的条件不成立,程序就要跳转的。当然是要去看汇编,里面才有跳转指令)
* switch 就更慢了,每个 case 都要比较一次。
* 其实有更简单、更快的算法 —— 用数组!
* 这叫 “查表法”,缺点就是空间消耗比较大。
* 定义一个有 256 个元素的数组,都不用写这个函数了,直接调用数组即可,函数里直接返回,还有调用函数的开销呢。
*/
int hexChar2int(char in_oChar)
{
    if (in_oChar >= '0' && in_oChar <= '9')
    {
        return (in_oChar - '0');
    }
    if (in_oChar >= 'A' && in_oChar <= 'F')
    {
        return (in_oChar - 'A' + 10);
    }
    if (in_oChar >= 'a' && in_oChar <= 'f')
    {
        return (in_oChar - 'a' + 10);
    }
    return 0;
}

/**
* “耗费空间比较大” 的话,我感觉 256 不是很大啊,毕竟是 byte 而已
* 要想运算快的话,就要用 int 数组!
* 这里有个字节对齐的问题,字节对齐的话,访问速度快,字节没对齐,指针要调整 2 次。
* 这个是操作系统的原理,“字节对齐” 这个概念对各种操作系统都适用。
*/
const int g_oArrIntTable[256] =
{
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
    13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0,
};

/**
* 用查表法,<< 4 也可以省掉,不过要用 2 个数组了
* in_oStrHex.at(i) 有一定的开销,建议不要用 stirng 传输入进来,传个指针(const char*)就够了
* 对大于 0 的整数,不要 /2 ,要 >>1
* 一个函数调用的开销有多大?如果不是 inline 的函数,开销和函数体内的运算比,就比较大了
*/
int hexStr2bytes(std::string in_oStrHex, byte* out_pArrBytes) {
    int t_iSize = (int)in_oStrHex.length();
    out_pArrBytes = new byte[t_iSize / 2];
   
    for (int i = 0; i < t_iSize; i += 2)
    {
        out_pArrBytes[i / 2] = (hexChar2int(in_oStrHex.at(i)) << 4) | hexChar2int(in_oStrHex.at(i + 1));
    }
   
    return t_iSize / 2;
}
/**
* 上述函数改进后的写法
* 这里直接传 out_pArrBytes 指针进来,内存分配在调用该方法之前就弄好(因为长度是已知的)
* in_iArrSize 是 out_pArrBytes 数组的长度;
* (in_iArrSize * 2) 是十六进制字符串的长度。
* 使用 new 的时候一定要防止失败时出现异常
* 用 new 的话,一定要放在 try{} catch{} 里,内存不够或者内存碎片过多没有连续内存分配的时候就会出错,
* 软件写得不好,长时间运行就有可能出现这种情况。出现异常,没有处理代码的话,软件马上就崩溃了
* 我们用 new<nothrow> , 分配后检查指针是否为 NULL。new 有 4 种用法,网上有相关资料。
*/
void hexStr2bytes(byte* out_pArrBytes, int in_iArrSize, const char* in_pArrCharHex)
{
    if (!out_pArrBytes)
    {
        printf("空指针!\n");
        return;
    }
   
    for (int i = 0; i < in_iArrSize << 1; i += 2)
    {
        char tmp_c0 = *(in_pArrCharHex + i);
        char tmp_c1 = *(in_pArrCharHex + i + 1);
        out_pArrBytes[i >> 1] = (g_oArrIntTable[tmp_c0] << 4) | g_oArrIntTable[tmp_c1];
    }
}

/**
* 这个函数返回一个栈对象,没啥问题,就是效率低了点
* t_oStrHex在函数结束的时候要析构销毁,重新产生一个临时对象返回
* 所以这个函数最好增加一个输出的形参,可以用指针。
* string t_oStrHex; 要执行一个构造函数
* return t_oStrHex; 要执行一次析构函数,一次构造函数产生临时对象,赋值后临时对象再执行一次析构函数。
* strHexElements 这个 string 也是没必要使用的,这些底层函数,可以全部用指针操作的,没必要用 string(注意指针别越界)
*/
string bytes2hexStr(byte* in_pArrBytes, int in_iSize)
{
    string t_oStrHex;
    string strHexElements(HEX_ELEMENTS);
    for (int i = 0; i < in_iSize; i ++)
    {
        t_oStrHex.append(1, strHexElements.at(0x0f & (in_pArrBytes[i] >> 4)));
        t_oStrHex.append(1, strHexElements.at(0x0f & in_pArrBytes[i]));
    }
    return t_oStrHex;
}

/**
* 改良后的函数
*/
const int g_oArrIntHex[16] =
{
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
void bytes2hexStr(string& out_oStrHex, byte* in_pArrBytes, int in_iArrSize)
{
    if (!in_pArrBytes)
    {
        printf("空指针!\n");
        return;
    }
   
    for (int i = 0; i < in_iArrSize; i ++)
    {
        out_oStrHex.append(1, g_oArrIntHex[0x0f & (in_pArrBytes[i] >> 4)]);
        out_oStrHex.append(1, g_oArrIntHex[0x0f & in_pArrBytes[i]]);
    }
}

//
//  main.cpp
//  MinaCppClient
//
//  Created by yang3wei on 7/27/13.
//
//

#include "ConvertUtil.h"

/**
* 输出:
* a7a8a9aa -- a7a8a9aa
*/
int main(int argc, const char * argv[]) {
   
    string t_oStrHex("a7a8a9aa");
   
    int t_iArrSize = (int)t_oStrHex.length() / 2;
    byte* t_pArrBytes = new byte[t_iArrSize];
   
    hexStr2bytes(t_pArrBytes, t_iArrSize, t_oStrHex.c_str());
   
    string t_oStrHex1;
   
    bytes2hexStr(t_oStrHex1, t_pArrBytes, t_iArrSize);
   
    printf("%s -- %s\n", t_oStrHex.c_str(), t_oStrHex1.c_str());
   
    return 0;
}

给我留言

留言无头像?