从文件中取两个十六进制字符并存储为具有关联十六进制值的字符

时间:2012-09-20 01:42:00

标签: c++ stream hex

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

因此,如果输入文件包含2a3123,我想抓取2a,并将数值(小数42)存储在字符中。

我试过

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

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

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

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

2 个答案:

答案 0 :(得分:3)

好吧我认为处理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可能会更快。

PS。改良版。使用简单的char[2]缓冲区并使用非格式化的写/读来通过缓冲区(get / write而不是operator<< / operator>>)移动数据。理由非常简单。我们不需要任何移动来移动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/

答案 1 :(得分:0)

您可以将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 casts to 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的系统。

相关问题