【问题标题】:Take two hex characters from file and store as a char with associated hex value从文件中获取两个十六进制字符并存储为具有相关十六进制值的字符
【发布时间】:2012-09-20 01:41:59
【问题描述】:

我想从流中取出接下来的两个十六进制字符,并将它们作为相关联的十六进制->十进制数值存储在一个字符中。

所以如果输入文件包含2a3123,我想抓取2a,并将数值(十进制42)存储在一个字符中。

我试过了

char c;
instream >> std::setw(2) >> std::hex >> c;

但这给了我垃圾(如果我用int 替换c,我得到signed int 的最大值)。

任何帮助将不胜感激!谢谢!

编辑:我应该注意,字符保证在适当的字符范围内,并且文件是有效的十六进制。

【问题讨论】:

    标签: c++ stream hex


    【解决方案1】:

    好的,我认为处理 ASCII 解码是个坏主意,并不能真正回答问题。

    我认为您的代码不起作用,因为 setw()istream::width() 仅在您阅读 std::stringchar* 时才有效。我猜是here

    如何使用标准 c++ iostream 转换器的优点。我想出了使用stringstream 类和string 作为缓冲区的想法。问题是将n 字符读入缓冲区,然后使用stringstream 作为转换器工具。

    我不确定这是否是最佳版本。应该不会吧。

    代码:

    #include <iostream>
    #include <sstream>
    
    int main(void){
        int c;
        std::string buff;
        std::stringstream ss_buff;
        std::cin.width(2);
        std::cin >> buff;
        ss_buff << buff;
        ss_buff >> std::hex >> c;
        std::cout << "read val: " << c << '\n';
    }
    

    结果:

    luk32@genaker:~/projects/tmp$ ./a.out 
    0a10
    read val: 10
    luk32@genaker:~/projects/tmp$ ./a.out 
    10a2
    read val: 16
    luk32@genaker:~/projects/tmp$ ./a.out 
    bv00   
    read val: 11
    luk32@genaker:~/projects/tmp$ ./a.out 
    bc01
    read val: 188
    luk32@genaker:~/projects/tmp$ ./a.out
    01bc
    read val: 1
    

    如您所见,它的抗错能力不是很强。尽管如此,在给定条件下工作,可以扩展成一个循环,最重要的是使用iostream 转换工具,所以你身边没有 ASCII 魔法。不过 C/ASCII 可能会更快。

    附言。改良版。使用简单的char[2] 缓冲区并使用非格式化的写入/读取将数据移动到缓冲区中(get/write 而不是operator&lt;&lt;/operator&gt;&gt;)。理由很简单。我们不需要任何幻想来移动 2 个字节的数据。但是,我们使用格式化提取器进行转换。为了方便起见,我把它做成了一个循环版本。但这并不是超级简单。我花了整整 40 分钟的时间来弄明白非常重要的台词。没有它们,提取适用于前 2 个字符。

    #include <iostream>
    #include <sstream>
    
    int main(void){
        int c;
        char* buff = new char[3];
        std::stringstream ss_buff;
        std::cout << "read vals: ";
        std::string tmp;
        while( std::cin.get(buff, 3).gcount() == 2 ){
           std::cout << '(' << buff << ") ";
           ss_buff.seekp(0); //VERY important lines
           ss_buff.seekg(0); //VERY important lines
           ss_buff.write(buff, 2);
           if( ss_buff.fail() ){ std::cout << "error\n"; break;}
           std::cout << ss_buff.str() << ' ';
           ss_buff >> std::hex >> c;
           std::cout << c << '\n';
        }
        std::cout << '\n';
        delete [] buff;
    }
    

    样本输出:

    luk32@genaker:~/projects/tmp$ ./a.out
    read vals: 0aabffc
    (0a) 0a 10
    (ab) ab 171
    (ff) ff 255
    

    请注意,c 未按预期读取。

    我在这里找到了所需的一切http://www.cplusplus.com/reference/iostream/

    【讨论】:

    • 很好的答案,@luk32!这非常有效地解决了我的问题。如果我有代表,我会投票,但我没有。
    【解决方案2】:

    您可以将 Char 转换为 int,而 int 将保存 char 的 ascii 值。例如,'0' 将是 48,'5' 将是 53。字母出现在更高的位置,因此 'a' 将被强制转换为 97,'b' 将被强制转换为 98 等等。所以知道这一点,您可以获取 int 值并减去48,如果结果大于 9,再减去 39。然后 char 0 将变为 int 0,char 1 变为 int 1 一直到 char a 设置为 int 10,char b 变为 int 11 等等。

    接下来,您需要将第一个的值乘以 16 并将其添加到第二个以考虑位移。使用您的 2a 示例。

    char 2 转换为 int 50。减去 48 得到 2。乘以 16 得到 32。 char a 转换为 int 97。减去 48 得到 49,这比 9 高,所以再减去 39 得到 10。将其添加到最后一个 (32) 的最终结果中,得到 42。

    代码如下:

    int HexToInt(char hi, char low)
    {
        int retVal = 0;
        int hiBits = (int)hi;
        int loBits = (int)low;
        retVal = Convert(hiBits) * 16 + Convert(loBits);
        return retVal;
    }
    
    int Convert(int in)
    {
        int retVal = in - 48;
        //If it was not a digit
        if(retVal > 10)
            retVal = retVal - 7;
        //if it was not an upper case hex didgit
        if(retVal > 15)
            retVal = retVal - 32;
        return retVal;  
    }
    

    第一个函数实际上可以写成一行:

     int HexToInt(char hi, char low)
     {
        return Convert((int)hi) * 16 + Convert((int)low);       
     }
    

    注意:这仅适用于小写字母,并且仅适用于使用 ASCII 的系统,即不适用于基于 IBM ebcdic 的系统。

    【讨论】:

    • 这行得通,但看起来很多。我可以做所需的数学运算,但我想知道 C++ 是否有一个好的速记符号。如果不是,那么我很乐意这样做。感谢您的回答!
    猜你喜欢
    • 2013-11-11
    • 2017-03-11
    • 2019-07-27
    • 2018-01-22
    • 2017-06-16
    • 1970-01-01
    • 2013-12-02
    • 2018-01-31
    • 1970-01-01
    相关资源
    最近更新 更多