【问题标题】:Hex to String Conversion C++/C/Qt?十六进制到字符串转换 C++/C/Qt?
【发布时间】:2010-11-18 12:37:50
【问题描述】:

我正在与一个以十六进制格式发送数据的外部设备连接。它的形式

> %abcdefg,+xxx.x,T,+yy.yy,T,+zz.zz,T,A*hhCRLF
  • CR LF 是回车换行
  • hh->校验和
  • %abcdefg -> 标题

上述数据包中的每个字符都以十六进制表示形式发送(xx、yy、abcd 等被替换为实际数字)。问题在于我将它存储在 const char* 中,并且在隐式转换期间,校验和说 0x05 被转换为 \0x05。这里 \0 是空字符终止我的字符串。当它不是时,这被认为是不正确的帧。虽然我可以将实现更改为处理原始字节(以十六进制形式),但我只是想知道是否还有其他出路,因为它大大简化了字节的处理。这就是程序员应该做的事情。

同样在cutecom(在LINUX RHEL 4上)我检查了串口上的数据,我们还注意到\0x05而不是5的校验和。 请注意,为了存储我正在使用的传入数据

//store data from serial here
unsigned char Buffer[SIZE];  

//convert to a QString, here is where problem arises 
QString str((const char*)Buffer); of \0

QString 是 Qt 的“字符串”克隆。库在这里不是问题,我也可以使用 STL,但 C++ 字符串库也在做同样的事情。以前有人尝试过这种类型的实验吗?请分享您的观点。

编辑

这是您也可以自己检查的示例代码:

#include <iostream>
#include <string>
#include <QString>
#include <QApplication>
#include <QByteArray>

using std::cout;
using std::string;
using std::endl;

int main(int argc,char* argv[])
{
    QApplication app(argc,argv);
    int x = 0x05;
    const char mydata[] = {
         0x00, 0x00, 0x03, 0x84, 0x78, 0x9c, 0x3b, 0x76,
               0xec, 0x18, 0xc3, 0x31, 0x0a, 0xf1, 0xcc, 0x99};
    QByteArray data = QByteArray::fromRawData(mydata, sizeof(mydata));
    printf("Hello %s\n",data.data());
    string str("Hello ");
    unsigned char ch[]={22,5,6,7,4};
    QString s((const char*)ch);
    qDebug("Hello %s",qPrintable(s));
    cout << str << x ;
    cout << "\nHello I am \0x05";
    cout << "\nHello I am " << "0x05";
    return app.exec();
}

【问题讨论】:

  • 对不起,大家注意到代码标签中的编码
  • 你想得到什么作为输出?源数组 0x00, 0x00, 0x03, 0x84, 0x78, 0x9c, 0x3b, 0x76, 0xec, 0x18, 0xc3, 0x31, 0x0a, 0xf1, 0xcc, 0x99 应该打印为 ... ?
  • @Jla3ep 我在串行端口上获取数据,从那里我在 unsigned char[FIXED SIZE] 缓冲区中读取数据。如我的帖子中所述,我将其转换为字符串。我正在研究的是一种消除接收到的数据中的 \0 字符或不会隐式转换为在十六进制值之前添加 \0 的转换的方法。
  • 是的,我明白了,但是您能否展示您所期望的实际数据和结果?在这一点上,我看不到如何从输入数据中获取 '\0'。符号 '\' 有 0x5C 代码,但我在你 mydata[] 数组中看不到它。
  • @Jla3ep。好的,这是十六进制的示例数据单个字符,因为设备正在发送 49,46,50,4a,4b,51,52,43,2c,31,32,33,2e,34,2c,54,2c,41 ,2c,2b,33,30,2e,30,30,2c,41,2c,2d,33,30,2e,30,30,2c,41,2a,05,0d,0a 倒数第三个字节 05 是产生问题的校验和。我将它收集在 unsigned char 缓冲区中,并通过将其转换为 const char* 来将此缓冲区转换为 QString。

标签: c++ qt


【解决方案1】:
QByteArray text = QByteArray::fromHex("517420697320677265617421");
text.data();            // returns "Qt is great!" 

【讨论】:

  • 我检查了你所建议的 text.data() 给出了同样的问题,因为它返回一个 char* 或 const char*:
【解决方案2】:

如果您的0x05 转换为char '\x05',那么您将没有十六进制值(只有在您将数字作为字符串时才有意义),而是二进制值。在 C 和 C++ 中,char 基本上只是另一种整数类型,几乎没有添加魔法。因此,如果您有5 并将其分配给char,您将得到系统编码定义为第五个字符的任何字符。 (在ASCII 中,这将是ENQ 字符,不管现在是什么意思。)

如果您想要的是 char '5',那么您需要将二进制值转换为其字符串表示形式。在 C++ 中,这通常使用流来完成:

const char ch = 5; // '\0x5'
std::ostringstream oss;
oss << static_cast<int>(ch);
const std::string& str = oss.str(); // str now contains "5"

当然,C std 库也提供了这种转换的函数。如果流媒体对您来说太慢,您可以尝试这些。

【讨论】:

  • 一个已获得 10,000 次浏览的问答,但没有对答案投赞成票。到现在为止。
  • @Duncan:确实,我很惊讶自己发现了这个。我想这是由于qt 标签引起的,它往往会吸引不信任 C++ 标准库的 Qt 粉丝。 :)感谢您的支持!
【解决方案3】:

我认为 c++ 字符串类通常设计用于处理以零结尾的字符序列。如果您的数据长度已知(看起来是这样),那么您可以使用 std::vector。这将提供字符串类的一些功能,同时忽略数据中的空值。

【讨论】:

  • std::string 实际上可以很好地处理包含'\0' 的字符序列。
  • 定义“非常好”。创建一个中间为空的 9 字符字符串 - “abcd\0efgh”。对字符串的每个操作将只考虑前 4 个字符 - 长度将返回 4,等等。
  • 事实并非如此——std::string 确实非常有能力保存二进制数据。例如,在上面的示例中,str.size() 将返回 9。
【解决方案4】:

正如我所见,您想消除控制 ASCII 符号。您可以通过以下方式进行:

#include <iostream>
#include <string>
#include <QtCore/QString>
#include <QtCore/QByteArray>

using namespace std;

// test data from your comment
char data[] = { 0x49, 0x46, 0x50, 0x4a, 0x4b, 0x51, 0x52, 0x43, 0x2c, 0x31,
                0x32, 0x33, 0x2e, 0x34, 0x2c, 0x54, 0x2c, 0x41, 0x2c, 0x2b,
                0x33, 0x30, 0x2e, 0x30, 0x30, 0x2c, 0x41, 0x2c, 0x2d, 0x33,
                0x30, 0x2e, 0x30, 0x30, 0x2c, 0x41, 0x2a, 0x05, 0x0d, 0x0a };

// functor to remove control characters
struct toAscii
{
  // values >127 will be eliminated too
  char operator ()( char value ) const { if ( value < 32 && value != 0x0d && value != 0x0a ) return '.'; else return value; }
};

int main(int argc,char* argv[])
{
  string s;
  transform( &data[0], &data[sizeof(data)], back_inserter(s), toAscii() );

  cout << s; // STL string

  // convert to QString ( if necessary )
  QString str = QString::fromStdString( s );
  QByteArray d = str.toAscii();

  cout << d.data(); // QString

  return 0;
}

上面的代码在控制台打印以下内容:

IFPJKQRC,123.4,T,A,+30.00,A,-30.00,A*.

如果你有连续的数据流,你会得到类似的东西:

IFPJKQRC,123.4,T,A,+30.00,A,-30.00,A*.
IFPJKQRC,123.4,T,A,+30.00,A,-30.00,A*.
IFPJKQRC,123.4,T,A,+30.00,A,-30.00,A*.
IFPJKQRC,123.4,T,A,+30.00,A,-30.00,A*.
IFPJKQRC,123.4,T,A,+30.00,A,-30.00,A*.

【讨论】:

  • 问题出在 jlaep。我想要 A* 之后的 5 并且它被打印为“。”。你现在明白这个问题了吗。 5 是校验和,给出为 0x05 但未打印
  • 例如,如果校验和为 0x49,那么您希望打印什么? “我”还是49
  • 我希望它能打印字符 1
  • 问题不在于 std::string 或 QString。它具有输出功能。您应该使用能够表示代码小于 32(十六进制为 0x20)的字符的函数。可以使用控制台中的 ncurses 库打印此类字符。您将根据 ASCII 表获得字符表示。对于 0x05,您将获得 (希望 SO 正确显示此字符)。
  • 还有大约 0x49。 0x49(十六进制)是 73(十二月)。是 I。1 的 ASCII 码为 0x31 (HEX) = 49 (DEC)。
猜你喜欢
  • 2012-01-24
  • 2018-01-31
  • 2017-08-12
  • 2014-06-09
  • 2018-06-06
  • 1970-01-01
  • 1970-01-01
  • 2011-11-12
  • 2015-04-24
相关资源
最近更新 更多