7

I have a server-client application that I'm working on that basically simulates a chat room. This is an assignment for school and the protocol specifications are somewhat strict.

I have a char array which will store all messages from a client.

The client must first send the length of the message as a uint8_t and then the message itself as a char array.

My problem is I need to store the uint8_t value that is sent before the actual message is sent but I can only use the message array to store any information coming from the client.

If I'm not mistaken the char array will not store the uint8_t that gets sent over unless I cast it somehow.

How can I convert the uint8_t to characters and back to uint8_t?

I've tried looking for a similar problem on here but couldn't find an example.

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 Answers 3

6

If you're on an architecture where uint8_t is a typedef to unsigned char (you most likely are), then simply take the first char and cast it to uint8_t:

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

It should work.

Sign up to request clarification or add additional context in comments.

1 Comment

I'll give that a shot. Thanks!
2

A char is exactly one byte (per definition of the C standard). Unless bytes aren't exactly 8 bits on your system (such systems exist, but I bet you've never used or even seen one), uint8_t and char are exactly the same data type.

char c = 5; uint8_t u = c; 

And if you can do something like that with a data type, then you can just cast pointers as you wish between these two data types:

 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' 

Actually you can even do that with strings, as a string is also just an array of characters, just one that is NUL terminated.

 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' 

The only thing you need to be careful is that the C standard does not define if char is signed or unsigned. Unlike integer types that are signed by default and only unsigned if you request so (long vs unsigned long for example), a char may be signed or unsigned by default. So if you need either one, you must use signed char or unsigned char as a data type. In practice that plays no role unless you perform certain math or logic operations on char values (which you probably shouldn't do in modern C code to begin with).

And since there is no way that your message can be bigger than 256 characters (as otherwise the length would not fit into uint8_t) and the length is always exactly one byte, I'd write the code as follows:

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) } 

And once more, as apparently some people fail to understand my second sentence already: Everything I wrote above it under the assumption, that bytes on your system are 8 bits long. This code is not portable to platforms where bytes have more or less than 8 bits, that's already what my second sentence clearly points out, but that doesn't make my reply wrong. If it wasn't allowed to write C code that is not portable to all existing platforms on earth, 90% of all existing C code would be forbidden. You know the platform you are working with and you know the platforms you are targeting with your app, so it's your responsibility to make sure the code is correct for all these platforms.

20 Comments

uint8_t isn't guaranteed to be a synonym for a character type. Thus using is to alias all types, as character types may be, is not portable.
@2501 Please explain which part of "Unless bytes aren't exactly 8 bits on your system (such systems exist, but I bet you've never used or even seen one), uint8_t and char are exactly the same data type." exactly didn't you understand? You do know the meaning of the word unless? Please stop putting words in my mouth that I have never said. And please also refrain from commenting answers that you have clearly not read.
@2501 A char is always exactly a byte, the C standard demands that! And if a byte has 8 bits on your system (and I explicitly warned that this doesn't have to be the case!!!), then uint8_t is also a byte. Please explain to the world, how a byte cannot be a byte, as the C standard also demands that if a native 8 bit type exists, uint8_t must be that type and if a char is 8 bits, then such a native type must exist. So your comment doesn't even make sense.
I'm not putting any "words in your mouth". Let's put that aside as it isn't relevant. Let me quote you: uint8_t and char are exactly the same data type. And I have responded to this: uint8_t isn't guaranteed to be a synonym for a character type. Thus they are not the same type. Standard allows that uint8_t is not a synonym for a character type, regardless of how many bits per byte are there. This is possible because of extended integer types. Please see: 7.20 @4 of the current standard. (Also please refrain from ad-hominem if you wish to have a debate with me.)
The comment i have made should have included your assumption of 8 bits per byte. This wasn't the issue with my argument as the conclusion is the same. C standard allows uintN_t types to be defined as extended integer types which are distinct from character types (7.20 §4 of the current standard). This is true regardless of how many bits per byte there are. Therefore an implementation may define 8 bits per byte and uint8_t as an extended integer type, which is a distinct type.
|
0

char can be easily converted to uint8_t, but I don't understand why do you need to store the length in message array. Why can't you store just in variable?

here are your examples of client and server with small changes that I think can be helpful:

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); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.