通用字节序转换函数

通用字节序转换函数

在分布式系统的软件开发过程中,字节序转换总是一件令人头疼的麻烦事,尤其是参数众多,函数上下层次较多的场合,极易发生某个参数漏转序的事故……

 

如果有一个通用的字节序转换函数,一次函数调用,全部参数一个不漏的实现转序,那就帅呆啦。参考python的struct库的设计思想,实现了通用字节序转换函数,先来看用户使用体验:

样例:

/* 静态结构体字节序转换 */
extern VOS_BOOL SwitchEndian(VOS_VOID *pStruct, const VOS_CHAR *pcFmt);

 

typedef struct {
    unsigned long nLong;
    unsigned short nShort;
 
    char acString[12];
    char resv[2];
 
    char cChar1;
    char cChar2;
    unsigned short usPad;
    double dDouble;
} DEMO_STRU;

 

int main()
{
    int aa = 100, bb=0;
    DEMO_STRU stDemo = {0x11223344, 0x5566, "It's a demo", 0,0, 'a', 'b', 0, 3.1415926};

    SwitchEndian(&stDemo, "LH12s2x2c2xQ"); // 传入格式化串,实现字节序转换

    return 0;
}

格式化串中各symbol的说明(与python的语法格式相似,是其简化版)

Symbol  Type                   Size  Remark
Q           U64,I64,double   8*N
L            U32,I32,float      4*N
H           U16,I16              2*N
c            U8, S8                1*N   Filling each separately
s            string                   1*N   Filling all together
x            padding               1*N   Filling zero automacly
space     Useless Seperator          Python中没有space,为提高可读而加

 

"LH12s2x2c2xQ" == "L H 12s 2x 2c 2x Q" == DEMO_STRU

 

结构描述串也是一种领域特定语言,通过简单的格式映射,将结构体(或二进制)信息转换成程序可识别的格式,让程序来实现繁琐且冗长的转换。

 

拼接fmt串的建议:

对于静态结构,格式化字符串可以写死,缺点是结构调整就得更新这个fmt串,这是无法避免的

对于动态结构,格式化字符串可以通过sprintf拼接

更智能的应用是:将所有待转序的结构体定义放在同一个.h中,写一段python脚本扫描结构自动生成fmt串,这样即使是结构存在嵌套(被嵌套的结构一定定义在嵌套结构之前),也能准确拼处正确的fmt串

 

结构描述的更多应用场景:

结构体打包,类似Python的struct.pack(...)

实例:

    DEMO_STRU stDemo;
    PackStruct(&stDemo, "!LH12sxx2c2xQ", 0x55667788, 10000, "abcdef", 'a', 'b', -123456.78901);

一句函数调用实现多个入参的赋值,fmt串前的!表示赋值的同时还转序(对于x即填充字段,自动赋0,不用指定参数传入)。这种写法比较节省代码行数,在串口调试构造结构体参数也非常便利。

 

计算结构长度,类似Python的struct.calcsize(...)

实例:

    printf("%d == %d\n", sizeof(DEMO_STRU), CalcSize("!LH12sxx2c2xQ"));

CalcSize是按一字节对齐计算结构尺寸,用来和sizeof结果比较,可以判断某结构是否紧压缩,调试用

 

结构成员打印,类似Python的print:

    VOS_BOOL PrintStruct(VOS_VOID *pStruct, const VOS_CHAR *pcFmt);

把结构的每个成员按类型dump出来,用于调试定位,相比数内存看数据高效得多

 

/*** A specification for symbols in format string
Symbol  Type             Size  Remark
Q       U64,I64,double   8*N
L       U32,I32,float    4*N
H       U16,I16          2*N
c       U8, S8           1*N   Filling each separately
s       string           1*N   Filling all together
x       padding          1*N   Filling zero automacly
!       Switch Endian Indicator
space   Useless Seperator    
***/

VOS_CHAR GetNextSymbol(const VOS_CHAR *pcFmt, VOS_INT *pnOffset, VOS_INT *pnEleCount)
{
    VOS_CHAR *pcCurr = (VOS_CHAR *)pcFmt + *pnOffset;
    VOS_INT nCount = 0;

    while (*pcCurr)
    {
        if (VOS_IsDigit(*pcCurr))
            nCount = nCount * 10 + (*pcCurr - '0');
        else {
            *pnOffset   = pcCurr + 1 - pcFmt;
            *pnEleCount = (0 == nCount) ? 1 : nCount;
            return *pcCurr;
        }
        pcCurr++;
    }
    return *pcCurr; // end symbol
}

VOS_BOOL PrintStruct(VOS_VOID *pStruct, const VOS_CHAR *pcFmt)
{
    VOS_INT nFmtIndex = 0, nRsltOffset = 0, nEleCount;
    VOS_CHAR *pcRslt = (VOS_CHAR *)pStruct;
    VOS_CHAR cSymbol;

#define PRINT_ELEMENT(tp, fmt, offset, cnt) for (VOS_INT _i=0;_i<(cnt);++_i,(offset)+=sizeof(tp)) printf(fmt" ", *(tp *)&pcRslt[offset])

    while (!bEnd) {
        cSymbol = GetNextSymbol(pcFmt, &nFmtIndex, &nEleCount);
        switch (cSymbol) {
            case 'L': // U32, I32, float
                PRINT_ELEMENT(VOS_UINT32, "%#x", nRsltOffset, nEleCount);
                break;
            case 'H': // U16, I16
                PRINT_ELEMENT(VOS_UINT16, "%#x", nRsltOffset, nEleCount);
                break;
            case 'c': // U8, S8
                PRINT_ELEMENT(VOS_CHAR, "%c", nRsltOffset, nEleCount);
                break;
            case 's': // string
                printf("%s ", &pcRslt[nRsltOffset]);
                nRsltOffset += nEleCount;
                break;
            case 'x': // pad VOS_CHAR, filling zero
                break;
            case 'Q': // U64, I64, double
                PRINT_ELEMENT(VOS_UINT64, "%lld", nRsltOffset, nEleCount);
                break;

            case '!': // host-network endian switch indicator
            case ' ': // seperator remark
                break;
            case '\0': // normal end
                bEnd = true;
                break;
            default: // unknown symbol
                return false;
        }
    }
#undef SET_ELEMENT

}

/* 相当于sizeof(),用于校验 */
VOS_INT CalcSize(const VOS_CHAR *pcFmt)
{
    VOS_UINT32 nTotal = 0;
    VOS_INT  nFmtIndex = 0, nEleCount = 0;
    VOS_CHAR cSymbol;

    while (true) {
        cSymbol = GetNextSymbol(pcFmt, &nFmtIndex, &nEleCount);

        switch (cSymbol) {
            case 'L': // U32, I32, float
                nTotal += nEleCount * sizeof(VOS_UINT32);
                break;
            case 'H': // U16, I16
                nTotal += nEleCount * sizeof(VOS_UINT16);
                break;
            case 'c': // U8, S8
            case 's': // string
            case 'x': // padding VOS_CHAR
                nTotal += nEleCount * sizeof(VOS_CHAR);
                break;
            case 'Q': // U64, I64, double
                nTotal += nEleCount * sizeof(VOS_UINT64);
                break;

            case '!': // host-network endian switch indicator
            case ' ': // seperator remark
                break;
            case '\0': // normal end
                return nTotal;
            default: // unknown symbol
                return -1;
        }
    }
    return false;
}

/* 静态结构体转序 */
VOS_BOOL SwitchEndian(VOS_VOID *pStruct, const VOS_CHAR *pcFmt)
{
    VOS_INT nFmtIndex = 0, nRsltOffset = 0, nEleCount;
    VOS_CHAR *pcRslt = (VOS_CHAR *)pStruct;
    VOS_CHAR cSymbol;

#define SW_ENDIAN(tp, offset, cnt, sw) for (VOS_INT _i=0;_i<(cnt);++_i,(offset)+=sizeof(tp)) *(tp *)&pcRslt[offset] = sw(*(tp *)&pcRslt[offset])
    while (true) {
        cSymbol = GetNextSymbol(pcFmt, &nFmtIndex, &nEleCount);

        switch (cSymbol) {
            case 'L': // U32, I32, float
                SW_ENDIAN(VOS_UINT32, nRsltOffset, nEleCount, VOS_HTONL);
                break;
            case 'H': // U16, I16
                SW_ENDIAN(VOS_UINT16, nRsltOffset, nEleCount, VOS_HTONS);
                break;
            case 'c': // U8, S8
            case 's': // string
            case 'x': // padding VOS_CHAR
                nRsltOffset += nEleCount;
                break;
            case 'Q': // U64, I64, double
                SW_ENDIAN(VOS_UINT32, nRsltOffset, nEleCount * 2, VOS_HTONL);
                break;

            case '!': // host-network endian switch indicator
            case ' ': // seperator remark
                break;
            case '\0': // normal end
                return true;
            default: // unknown symbol
                return false;
        }
    }
#undef SW_ENDIAN
    return false;
}

// 按指定格式填充结构体(紧压缩),支持转序
VOS_BOOL PackStruct(VOS_VOID *pStruct, const VOS_CHAR *pcFmt, ...)
{
    VOS_INT nFmtIndex = 0, nRsltOffset = 0, nEleCount;
    VOS_CHAR *pcRslt = (VOS_CHAR *)pStruct;
    VOS_CHAR cSymbol;
    VOS_BOOL bEnd = false, bSwEndian=false;
    va_list pArgList;

    va_start(pArgList, pcFmt);

#define SET_ELEMENT(tp, offset, cnt) for (VOS_INT _i=0;_i<(cnt);++_i,(offset)+=sizeof(tp)) *(tp *)&pcRslt[offset] = (tp)va_arg(pArgList, tp)

    while (!bEnd) {
        cSymbol = GetNextSymbol(pcFmt, &nFmtIndex, &nEleCount);
        switch (cSymbol) {
            case 'L': // U32, I32, float
                SET_ELEMENT(VOS_UINT32, nRsltOffset, nEleCount);
                break;
            case 'H': // U16, I16
                SET_ELEMENT(VOS_UINT16, nRsltOffset, nEleCount);
                break;
            case 'c': // U8, S8
                SET_ELEMENT(VOS_CHAR, nRsltOffset, nEleCount);
                break;
            case 's': // string
                VOS_StrNCpy(&pcRslt[nRsltOffset], (VOS_CHAR *)va_arg(pArgList, VOS_CHAR *), nEleCount);
                nRsltOffset += nEleCount;
                break;
            case 'x': // pad VOS_CHAR, filling zero
                VOS_MemSet(&pcRslt[nRsltOffset], 0, nEleCount);
                nRsltOffset += nEleCount;
                break;
            case 'Q': // U64, I64, double
                SET_ELEMENT(VOS_UINT32, nRsltOffset, nEleCount * 2);
                break;

            case '!': // host-network endian switch indicator
                bSwEndian = true;
                break;
            case ' ': // seperator remark
                break;
            case '\0': // normal end
                bEnd = true;
                break;
            default: // unknown symbol
                return false;
        }
    }
#undef SET_ELEMENT
    va_end(pArgList);

    if (bSwEndian) SwitchEndian(pStruct, pcFmt);

    return true;
}

/************************************************************************/

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值