如何将字符数组转换为uint8_t?

4
我正在开发一个服务器-客户端应用程序,基本上模拟了一个聊天室。这是一项学校作业,协议规范要求有些严格。
我有一个字符数组,将存储来自客户端的所有消息。
客户端必须首先将消息长度作为uint8_t发送,然后将消息本身作为char数组发送。
我的问题是,我需要存储在实际消息发送之前发送的uint8_t值,但我只能使用消息数组来存储从客户端发来的任何信息。
如果我没有弄错,char数组将不会存储发送的uint8_t除非我以某种方式进行转换。
我该如何将uint8_t转换为字符并重新转换为uint8_t?
我已经尝试在这里寻找类似的问题,但没有找到示例。
server.c
char msg[100];
recv(clients_sd, msg, sizeof(msg), 0);
uint8_t len; /* store the length of the message here */
char message_received[len];
recv(clients_sd, message_received, sizeof(message_received), 0); /* get and store the message here */

client.c

uint8_t length = 21;
char clients_message[] = "Hi how are you today?";
send(servers_sd, &length, sizeof(length), 0);
send(serers_sd, &clients_message, sizeof(clients_message), 0);
3个回答

5

如果您使用的架构中uint8_tunsigned chartypedef(您很可能是这样),那么只需取第一个char并将其转换为uint8_t即可:

length = (uint8_t)(message_received[0]);

应该能够正常工作。


我会试一试。谢谢! - fatalError

2

char是恰好占用一个字节的数据类型(根据C标准的定义)。除非你的系统上字节不恰好是8位(这种系统确实存在,但我打赌你从未使用过或甚至见过),否则uint8_tchar是完全相同的数据类型。

char c = 5;
uint8_t u = c;

如果你可以使用某种数据类型做到这样,那么你就可以随意将指针转换为这两种数据类型之间:

 char c[] = { 'H', 'e', 'l', 'l', 'o' };
 uint8_t * u = (uint8_t *)c;
 uint8_t x = u[1];
 // x is 101, which is the ASCII char code of 'e'

实际上,您甚至可以使用字符串来实现这一点,因为字符串也只是一个字符数组,只不过它以NUL结尾。
 char * c = "Hello"; 
 // "Hello" is in fact just { 'H', 'e', 'l', 'l', 'o', '\0' }
 uint8_t * u = (uint8_t *)c;
 uint8_t x = u[1];
 // x is 101, which is the ASCII char code of 'e'

唯一需要注意的是,C标准没有定义char是有符号还是无符号。整数类型默认为有符号,只有在请求时才使用无符号(例如long vs unsigned long),但char默认可以是有符号或无符号的。因此,如果需要使用其中之一,则必须将signed charunsigned char作为数据类型。实际上,除非对char值执行某些数学或逻辑操作(在现代C代码中最好不要这样做),否则这对结果没有影响。
而且,由于您的消息长度不可能超过256个字符(否则长度将不适合uint8_t),并且长度始终正好为一个字节,因此我会按以下方式编写代码:
uint8_t messageLength = 0;
ssize_t bytesRead = recv(clients_sd, &messageLength, 1, 0);
if (bytesRead == -1) {
     // Handle read error
}
if (bytesRead == 0) {
     // Handle end of stream
}

char message[256];
bytesRead = recv(clients_sd, message, messageLength, 0);
if (bytesRead == -1) {
     // Handle read error
}
if (bytesRead == 0) {
     // Handle end of stream
}
if (bytesRead < messageLength) {
     // Handle truncated message (message too small)
}

再说一遍,显然有些人不理解我的第二句话:我上面写的一切都是在假设你系统上的字节长度为8位的情况下。这段代码不能在字节长度大于或小于8位的平台上移植,这已经是我的第二句话明确指出的了,但这并不意味着我的回答是错误的。如果不允许编写在地球上所有现有平台上都可移植的C代码,那么90%的现有C代码都将被禁止。你知道你正在使用的平台,也知道你的应用程序的目标平台,因此你有责任确保代码对所有这些平台都是正确的。


1
uint8_t并不保证是字符类型的同义词。因此,使用它来别名所有类型,因为字符类型可能不具备可移植性。 - 2501
@2501请解释一下你没有理解的“除非在你的系统上字节不是恰好8位(这样的系统存在,但我敢打赌你从未使用过或甚至见过),否则uint8_t和char是完全相同的数据类型。”部分是什么?你知道unless这个词的意思吗?请不要曲解我的话,我从未说过的话。并且请不要评论你明显没有阅读过的答案。 - Mecki
是的,它的大小确实是一个字节。但类型也很重要,特别是在指针转换中,正如你回答中展示的那样。它可以被定义为与char、signed char或unsigned char不同的类型。这很重要,因为严格别名规则的违反会导致未定义行为。 - 2501
在这种情况下,这并不重要。uint8_t是8位的,没有填充(7.20.1.1 P1)。如果平台无法提供它,就不能完全提供uint8_t作为数据类型(7.20.1.1 P3)。因此,我可以依赖于uint8_t[10]在内存中是80个连续的位,并且每8个位组成一个int值。char始终正好是一个字节(3.6到3.7.1),不必是8位,但如果字节是8位,则char必须是8位。将8位强制转换为8位是安全的,如果两者都未填充(标准保证),则将内存指针强制转换为8位数组的内存指针是安全的。 - Mecki
在8位字节系统上,uint8_t可以别名为char,因为它是“兼容类型”。我从未声称这适用于所有系统。不,C标准没有在任何地方说过这一点,因为它不必这样做。 C标准说,任何兼容类型都可以别名为任何具体类型,并且uint8_t是8位字节系统上的兼容类型(不是通用的,仅在该系统上,并且由于该标准不知道或不关心您的系统,因此它不会指出这些特定于系统的事实,但这并不意味着它们是错误的)。在这里,“兼容类型”就是标准所要说的全部内容。 - Mecki
显示剩余15条评论

0

char 可以很容易地转换为 uint8_t,但我不明白为什么需要在消息数组中存储长度。为什么不能只存储在变量中呢?

这里是您的客户端和服务器示例,我认为进行了一些小改动,可能会有所帮助:

server.c

uint8_t len; /* store the length of the message here */
recv(clients_sd, &len, sizeof(len), 0);    
char message_received[len];
recv(clients_sd, message_received, len, 0); /* get and store the message here */

client.c

uint8_t length = 21;
char clients_message[] = "Hi how are you today?";
send(servers_sd, &length, sizeof(length), 0);
send(serers_sd, clients_message, length, 0);

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