将char[]转换为Qstring并添加额外的3个字符

4

TL;DR:

我正在实现一个客户端-服务器系统,客户端通过设置大小为char [256]的字符缓冲区请求数据。

服务器以两个阶段的响应方式进行回复。首先,使用大小为char [20]的头部缓冲区发送“头数据包”,其中包含随后要发送的数据包数量和最大包大小(以分配“数据”缓冲区)。

假设从服务器发送的文本如下所示:

QString text = QString("TOKEN=1SOMETOKENSTRING123;");
//length of text = 26 char

使用以下方法将“标题包”成功接收、解析并转换为QString,无任何缺陷:

//header
char header_buffer[20];
bzero(header_buffer, sizeof (header_buffer));
//assign header_buffer using socket.recv()
QString header = QString(header_buffer);

这项工作已经成功完成。

问题信息:

头部已解析,输出属性大小(最大数据包大小)和计数(随后的“数据”包数)。

问题所在区域:

//data packet section

//returns the size of largest packet using the received "header packet" - done successfully
int maxSize = getMaxPacketSize(header_buffer);
//maxSize = 27 char, which is the length of the 'text' String sent from the server, thus

char data_buffer[maxSize]; //char[27]
bzero(data_buffer, sizeof (data_buffer));
//assign data_buffer using socket.recv()
QString data = QString(data_buffer);
qDebug() << data_buffer;   CORRECT  //displays "TOKEN=1SOMETOKENSTRING123;"
qDebug() << data;          ERROR    //displays "TOKEN=1SOMETOKENSTRING123;UUU" 

具体问题:

从char[]创建新的QString会在字符串末尾添加3个'U'字符:

基本示例:

char cArray[27] //assume it has contents to fill all, size/count = 27
QString str = QString(cArray);
int len = str.length();
//len = 30, last 3 char of str = "UUU"

数据示例(实际数据):

    int packetSize = getMaxPacketSize(buffer); buffer[20] = "COUNT=2;SIZE=27;\000\000\000\000"
    char packet[packetSize]; // = 27
    size_t size = sizeof (packet); // = 27 
    bzero(packet, sizeof (packet));

    if (recv(sockfd,packet,sizeof (packet),0) < 0) {
        qDebug() << "ERROR netman: reading data from socket";
        //more code here
    }

    //Add packet to packet_data list

    //NOTE : QList<QString> packet_data = QList<QString>();
    //NOTE: packet[27] = "TOKEN=a7nCrDbaycWx2JzMir4m;"

    packet_data.insert(packetSize-packetNum,QString(packet)); 
    QString d = packet_data.first(); d = "TOKEN=a7nCrDbaycWx2JzMir4m;UUU"

为了更详细地描述问题,以下是调试器数据

Locals      
    d   "TOKEN=a7nCrDbaycWx2JzMir4m;UUU"    QString
        [0] 'T'     84  0x0054  QChar
        [1] 'O'     79  0x004f  QChar
        [2] 'K'     75  0x004b  QChar
        [3] 'E'     69  0x0045  QChar
        [4] 'N'     78  0x004e  QChar
        [5] '='     61  0x003d  QChar
        [6] 'a'     97  0x0061  QChar
        [7] '7'     55  0x0037  QChar
        [8] 'n'     110 0x006e  QChar
        [9] 'C'     67  0x0043  QChar
        [10]    'r'     114 0x0072  QChar
        [11]    'D'     68  0x0044  QChar
        [12]    'b'     98  0x0062  QChar
        [13]    'a'     97  0x0061  QChar
        [14]    'y'     121 0x0079  QChar
        [15]    'c'     99  0x0063  QChar
        [16]    'W'     87  0x0057  QChar
        [17]    'x'     120 0x0078  QChar
        [18]    '2'     50  0x0032  QChar
        [19]    'J'     74  0x004a  QChar
        [20]    'z'     122 0x007a  QChar
        [21]    'M'     77  0x004d  QChar
        [22]    'i'     105 0x0069  QChar
        [23]    'r'     114 0x0072  QChar
        [24]    '4'     52  0x0034  QChar
        [25]    'm'     109 0x006d  QChar
        [26]    ';'     59  0x003b  QChar
        [27]    'U'     85  0x0055  QChar
        [28]    'U'     85  0x0055  QChar
        [29]    'U'     85  0x0055  QChar
    message "AUTH;U=user@example;P=Pass;"   char *
    packet  "TOKEN=a7nCrDbaycWx2JzMir4m;"   char [27]
    packetNum   1   int
    packetSize  27  int
    s   "COUNT=2;SIZE=27;"  QString
    size    27  size_t
    this    @0x7fffffffd190 netman
        buffer  "COUNT=2;SIZE=27;\000\000\000\000"  char [20]
        cli_addr    @0x7fffffffd1c0 sockaddr_in
        clilen  1431695692  socklen_t
        n   1436538608  int
        newsockfd   32767   int
        packet_data <1 items>   QList<QString>
        serv_addr   @0x7fffffffd1b0 sockaddr_in
        server  @0x7ffff5f071c0 hostent
        sockfd  13  int

我不知道这3个额外字符来自何方!

有任何建议/想法的人吗?


这并不能真正解决你的问题,但是如果你像这样分配header_buffer数组,就可以放弃bzero()调用:char data_buffer[maxSize]={};这将把数组的所有元素都设置为0。 - antred
1
顺便问一下,你是怎么编译这个的?C++不支持可变长度数组。换句话说,数组的长度必须在编译时就已知,但你在这行代码中使用了运行时值来设置数组的大小:char data_buffer[maxSize]; //char[27] - antred
你为 null 保留了一个字符,但缓冲区实际上是否以 null 结尾? - dtech
2个回答

3
这里的主要问题是你将char*传递给了期望c字符串的函数。即,一个以零值结尾的字符串。但是,你从套接字中读取的输入没有包含这样的字节。
超出数组范围的读取是未定义的行为,但在这种情况下,很容易推断出会发生什么:字节会被读取直到找不到空值,并且很快就会找到(在另外3个字节之后)1
你可以通过使用从数组中精确读取所需字节数的函数来轻松解决它。
最简单的方法是使用QStringfromUtf8fromLatin1fromLocal8Bit成员函数来提供你想要读取的字节数。
QString str = QString::fromUtf8(cArray, number_of_bytes);

话虽如此,考虑使用QByteArray来处理从网络读取的数据:

QByteArray data(cArray, number_of_bytes);

1 对于未定义行为发生的原因的推理应该保持谨慎,因为编译器在探测到它发生时可以自由地执行几乎任何操作。


尝试使用QByteArray,结果与QString()相同,我将尝试使用Latin编码,我记得在服务器端使用了local8bit编码,认为这可能是导致此问题的原因,我会让你知道。 - CybeX
@KGCybeX,你正在传递正确的字节值吗? - krzaq
刚刚尝试了这个代码:QByteArray ba = packet;QString st = ba.toStdString().c_str();QString stri = QString(packet);。st和stri的输出结果相同,都包含末尾的UUU。我还修改了服务器端的代码,也使用了QByteArray。 - CybeX
1
@KGCybeX,那样可能行不通。你应该尝试使用QByteArray的构造函数,它带有第二个参数,用于指定要读取的字节数。 - krzaq
谢谢,这解决了问题。如果可能的话,请编辑您的答案并包括这个问题以及我可能导致的错误的简短说明,即三个“UUU”的原因。 - CybeX
@KGCybeX 编辑过了,如果还不够清晰,请告诉我。 - krzaq

1
你使用的编译器是什么(版本和cppflags)?
//returns the size of largest packet using the received "header packet" - done successfully
int maxSize = getMaxPacketSize(header_buffer);
//maxSize = 27 char, etc

char data_buffer[maxSize]; //char[27]
//               ^
// really?-------+ Variable Length Array on standard C++?
// does this even compile?

VLA on SO

cppreference.com上的数组声明:

noptr-declarator [ expr(optional) ] attr(optional)

...

  • expr - 一个整数常量表达式(C++14之前),或类型为std::size_t的转换后常量表达式(自C++14起),其计算结果大于零的值

上述内容的相关性如何:如果代码编译通过(假设有警告而非错误),这可能导致未定义行为 - 例如,后续的函数调用(例如 QString 构造函数)覆盖了 VLA 的一部分(在堆栈上),在这种情况下擦除了空字符,可能会在其他情况下产生其他影响。
如果发生这种情况,在调试时检查缓冲区的内容(在最后一个示例中是 packet 变量而非 d 变量)应该会显示修改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接