将 char[] 转换为 Qstring 添加额外的 3 个字符
Convert char[] to Qstring adding extra 3 chars
TL;DR 见底部
背景信息:(透视)
我正在实现一个client-server,客户端请求数据,通过设置的字符缓冲区发送,设置大小为字符[256]
服务器以 2 阶段响应实物响应,
首先使用 header 缓冲区发送 'header packet'(在客户端和服务器上,大小为 char[20]),其中包含要跟随的数据包数量和要发送的最大数据包的大小(分配"data" 缓冲区),
assume the text sent from server is as follows
QString text = QString("TOKEN=1SOMETOKENSTRING123;");
//length of text = 26 char
此 "header packet" 已成功接收、解析和实现,在转换为 QString 时没有任何缺陷,方法是:
//header
char header_buffer[20];
bzero(header_buffer, sizeof (header_buffer));
//assign header_buffer using socket.recv()
QString header = QString(header_buffer);
成功完成
问题信息:
header 被解析并输出属性大小(最大数据包大小)和计数('data' 数据包的数量)
这里是问题所在:
//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;[=14=]0[=14=]0[=14=]0[=14=]0"
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;[=15=]0[=15=]0[=15=]0[=15=]0" 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 个额外的字符是从哪里来的!
有人suggestions/ideas吗?
这里的主要问题是您将 char*
传递给需要 C 字符串的函数。即,末尾为零值的字符串。但是您从套接字输入的内容不包含这样一个字节。
读取数组末尾是未定义的行为,但在这种情况下很容易推断会发生什么:读取字节直到找不到空值,并且很快就会找到它(在 3 个字节之后)1.
您可以通过使用函数来轻松修复它,这些函数获取它们应该从数组中读取的确切字节数。
最简单的方法是使用QString
的成员函数fromUtf8
or fromLatin1
or fromLocal8Bit
提供你要读取的字节数:
QString str = QString::fromUtf8(cArray, number_of_bytes);
也就是说,考虑使用 QByteArray
从网络读取数据:
QByteArray data(cArray, number_of_bytes);
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
- an integral constant expression
(until C++14) a converted constant expression of type std::size_t
(since C++14), which evaluates to a value greater than zero
上面的相关性如何:如果代码编译(假设有警告而不是错误),这可能会导致未定义的行为 - 例如随后的函数调用(例如 QString 构造函数)覆盖了 VLA 的一部分(在堆栈上),在这种情况下消除了 nul 终止字符,在其他情况下可能会产生其他影响。
如果发生这种情况,检查(在调试时)缓冲区的内容(在最后一个示例中,packet
var 而不是 d
var)应该会发现更改。
TL;DR 见底部
背景信息:(透视)
我正在实现一个client-server,客户端请求数据,通过设置的字符缓冲区发送,设置大小为字符[256]
服务器以 2 阶段响应实物响应, 首先使用 header 缓冲区发送 'header packet'(在客户端和服务器上,大小为 char[20]),其中包含要跟随的数据包数量和要发送的最大数据包的大小(分配"data" 缓冲区),
assume the text sent from server is as follows
QString text = QString("TOKEN=1SOMETOKENSTRING123;");
//length of text = 26 char
此 "header packet" 已成功接收、解析和实现,在转换为 QString 时没有任何缺陷,方法是:
//header
char header_buffer[20];
bzero(header_buffer, sizeof (header_buffer));
//assign header_buffer using socket.recv()
QString header = QString(header_buffer);
成功完成
问题信息:
header 被解析并输出属性大小(最大数据包大小)和计数('data' 数据包的数量)
这里是问题所在:
//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;[=14=]0[=14=]0[=14=]0[=14=]0"
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;[=15=]0[=15=]0[=15=]0[=15=]0" 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 个额外的字符是从哪里来的!
有人suggestions/ideas吗?
这里的主要问题是您将 char*
传递给需要 C 字符串的函数。即,末尾为零值的字符串。但是您从套接字输入的内容不包含这样一个字节。
读取数组末尾是未定义的行为,但在这种情况下很容易推断会发生什么:读取字节直到找不到空值,并且很快就会找到它(在 3 个字节之后)1.
您可以通过使用函数来轻松修复它,这些函数获取它们应该从数组中读取的确切字节数。
最简单的方法是使用QString
的成员函数fromUtf8
or fromLatin1
or fromLocal8Bit
提供你要读取的字节数:
QString str = QString::fromUtf8(cArray, number_of_bytes);
也就是说,考虑使用 QByteArray
从网络读取数据:
QByteArray data(cArray, number_of_bytes);
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
- anintegral constant expression
(until C++14) a convertedconstant expression of type std::size_t
(since C++14), which evaluates to a value greater than zero
上面的相关性如何:如果代码编译(假设有警告而不是错误),这可能会导致未定义的行为 - 例如随后的函数调用(例如 QString 构造函数)覆盖了 VLA 的一部分(在堆栈上),在这种情况下消除了 nul 终止字符,在其他情况下可能会产生其他影响。
如果发生这种情况,检查(在调试时)缓冲区的内容(在最后一个示例中,packet
var 而不是 d
var)应该会发现更改。