将带有前导“0x”的十六进制字符串转换为C++中的有符号短字符串?

Posted

技术标签:

【中文标题】将带有前导“0x”的十六进制字符串转换为C++中的有符号短字符串?【英文标题】:Convert hexadecimal string with leading "0x" to signed short in C++? 【发布时间】:2010-12-02 00:39:12 【问题描述】:

我找到了使用strtol 将十六进制字符串转换为signed int 的代码,但我找不到短整数(2 个字节)的内容。这是我的一段代码:

while (!sCurrentFile.eof() )

    getline (sCurrentFile,currentString);
    sOutputFile<<strtol(currentString.c_str(),NULL,16)<<endl;

我的想法是读取具有 2 字节宽值的文件(如 0xFFEE),将其转换为带符号的 int 并将结果写入输出文件。执行速度不是问题。

我可以找到一些方法来避免这个问题,但我想使用“单线”解决方案,所以也许你可以为此提供帮助:)

编辑:文件如下所示:

0x0400
0x03fe
0x03fe
...

编辑:我已经尝试过使用十六进制运算符,但在这样做之前我仍然需要将字符串转换为整数。

// This won't work as currentString is not an integer
myInt << std::hex << currentString.c_str(); 

【问题讨论】:

您的输入文件是什么样的?如果没有这些信息,很难提出任何建议。 请看 strtol 返回 long , not signed int, sscanf 返回一个 int,但 scanf 系列函数的返回值是它们成功转换的字段数。虽然我很欣赏这种宣传,但你抄错了。 :) edit : 我的错,我想减少代码并且没有看我在做什么 - 这是我工作日的结束:) 看起来 Loki 是唯一真正回答这个问题的人。 【参考方案1】:

您是否考虑过带有“%hx”转换限定符的sscanf

【讨论】:

或者,如果您没有任何特别需要使用 C++ I/O 流,请直接使用 fscanf... 取决于您控制的代码量。 fscanf 和 sscanf 是我通常处理这个问题的方式。我现在有一个程序可以读取与此类似的 CRC 十六进制字符串:sscanf(cstr_fileCRC, "%lX", &ul_fileCRC); 问题标记为 C++。另外,sscanf 通常不受欢迎,因为它带有与安全相关的问题。【参考方案2】:

您可能可以将stringtream 类的 >> 运算符与十六进制操纵器一起使用。

【讨论】:

正是我需要的,它只有一行大! 你应该提供一个例子。前导 0x 似乎会导致解析失败。【参考方案3】:

如果您确定来自currentString.c_str() 的数据可以信任,那么您也可以轻松做到

myInt << std::hex << atoi(currentString.c_str());

【讨论】:

当 C++ 流已经完成所有工作时,为什么还要使用 C 函数。 问题标记为 C++,而不是 C。【参考方案4】:

如果您知道数据总是采用这种格式,您就不能这样做:

myInt << std::hex << currentString.c_str() +2; // skip the leading "0x"

【讨论】:

这里 std::hex 在处理字符串时什么都不做。您只是重新打印您读取的字符串(减去前两个字符)。【参考方案5】:

这应该很简单:

std::ifstream   file("DataFile");
int             value;

while(file >> std::hex >> value)  // Reads a hex string and converts it to an int.

    std::cout << "Value: " << std::hex << value << "\n";

当我们谈论文件时: 您应该这样做:

while (!sCurrentFile.eof() )

    getline (sCurrentFile,currentString);
    ... STUFF ...

这是因为当您阅读最后一行时,它确实设置了 EOF。因此,当您循环然后读取最后一行之后的行时,getline() 将失败,您将对 currentString 中的内容从上次设置时开始执行 STUFF。所以实际上你将处理最后一行两次。

循环文件的正确方法是:

while (getline(sCurrentFile,currentString))

    // If the get fails then you have read past EOF and loop is not entered.
    ... STUFF ...

【讨论】:

【参考方案6】:
// convert unsigned-integer to it's hexadecimal string represention
// 0x12345678 -> '12345678'
// N is BYTE/WORD/UINT/ULONGLONG
// T is char or wchar_t
template <class N, class T> inline T* UnsignedToHexStr(N    n             ,  // [i  ]
                                                       T*   pcStr         ,  // [i/o] filled with string
                                                       UINT nDigits       ,  // [i  ] number of digits in output string / 0 (auto)
                                                       bool bNullTerminate ) // [i  ] whether to add NULL termination

    if ((N)-1 < (N)1)              // if type of N is floating-point / signed-integer
        if (::IsDebuggerPresent())
        
            ::OutputDebugString(_T("UnsignedToHexStr: Incorrect type passed\n"));
            ::DebugBreak();
        

    if (!nDigits)
        nDigits= GetUnsignedHexDigits(n);

    if (1 == sizeof(T))
    
        const char _czIntHexConv[]= "0123456789ABCDEF";
        for (int i= nDigits-1; i>= 0; i--)
        
            char* pLoc= (char*)&pcStr[i];
            *pLoc= _czIntHexConv[n & 0x0F];
            n >>= 4;
        
    
    else
    
        const wchar_t _czIntHexConv[]= L"0123456789ABCDEF";
        for (int i= nDigits-1; i>= 0; i--)
        
            wchar_t* pLoc= (wchar_t*)&pcStr[i];
            *pLoc= _czIntHexConv[n & 0x0F];
            n >>= 4;
        
    

    if (bNullTerminate)
        pcStr[nDigits]= 0;

    return pcStr;




// --------------------------------------------------------------------------
// convert unsigned-integer in HEX string represention to it's numerical value
// '1234' -> 0x1234
// N is BYTE/WORD/UINT/ULONGLONG
// T is char or wchar_t
template <class N, class T> inline bool HexStrToUnsigned(const T* pczSrc                    ,
                                                         N&       n                         ,
                                                         bool     bSpecificTerminator= false,  // whether string should terminate with specific terminating char
                                                         T        cTerminator        = 0     ) // specific terminating char

    n= 0;

    if (!pczSrc)
        return false;

    while ((32 == *pczSrc) || (9 == *pczSrc))
        pczSrc++;

    bool bLeadZeros= *pczSrc == _T('0');
    while (*pczSrc == _T('0')) // skip leading zeros
        pczSrc++;

    BYTE nMaxDigits= 2*sizeof(N);
    BYTE nDigits   = 0          ;

    while (true)
    
        if ( (*pczSrc >= _T('0')) && (*pczSrc <= _T('9')))
         if (nDigits==nMaxDigits) return false; n= (n<<4) + (*pczSrc-_T('0')   ); pczSrc++; nDigits++; continue; 

        if ( (*pczSrc >= _T('A')) && (*pczSrc <= _T('F')))
         if (nDigits==nMaxDigits) return false; n= (n<<4) + (*pczSrc-_T('A')+10); pczSrc++; nDigits++; continue; 

        if ( (*pczSrc >= _T('a')) && (*pczSrc <= _T('f')))
         if (nDigits==nMaxDigits) return false; n= (n<<4) + (*pczSrc-_T('a')+10); pczSrc++; nDigits++; continue; 

        if (bSpecificTerminator)
            if (*pczSrc != cTerminator)
                return false;

        break;
    

    return (nDigits>0) || bLeadZeros; // at least one digit

【讨论】:

你显然很生气 :-)

以上是关于将带有前导“0x”的十六进制字符串转换为C++中的有符号短字符串?的主要内容,如果未能解决你的问题,请参考以下文章

c ++,stl。将带有rgb颜色的字符串转换为3个int值?

获取字符串中的每个字符并将其转换为 Hex c++?

在 C++ 中将十六进制字符串转换为字节数组

将动态数据转换为数组中的十六进制

使用前导零将十六进制转换为二进制

在 Java 中,如何将字节数组转换为十六进制数字字符串,同时保持前导零? [复制]