0
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

char* createMSG(uint8_t i,uint32_t port);

int strlen(char* tmp);
uint32_t user_port = 5000;

int main(int argc, char** argv) {
    char *msg;
    uint8_t i;
    i = 1;  
    msg = createMSG(i,user_port);
    printf("Port: %d",*(msg+2));
}

char* createMSG(uint8_t i,uint32_t port) {
    char *buff; 
    buff = (char*) malloc(6);
    uint8_t id;
    id = 2;
    memcpy(buff, &id, sizeof(uint8_t));
    memcpy(buff+1, &i, sizeof(uint8_t));
    memcpy(buff+2, &port, sizeof(uint32_t));
    return buff;
}

The output is: "Port: -120". It seems there is some overflow. But uint32_t should be big enough for 5000. When using 22 instead of 5000, everything is ok.

Why?

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
user1324258
  • 561
  • 2
  • 8
  • 25
  • 2
    Also `%d` is not the correct format for an `uint32_t`. First that would be a format for a signed value and not unsigned. Then you usually don't know if `unsigned` corresponds to a 32 bit type. The correct macro for the format is `PRIu32` something like `"Port: %" PRIu32 "\n"` (yes this is ugly). Also don't forget the `\n` at the end of a `printf` to be sure that you see the output. – Jens Gustedt May 18 '12 at 20:53
  • Hi, i never heard about PRIu32. From now i will PRIu32, to prevent unexpected behavior. Till now %d did always his job. When sending msg with sendto(), i am getting a wrong value for *(msg+2) again, even if i use `(uint32_t*)`. – user1324258 May 18 '12 at 21:08

2 Answers2

4

Because *(msg+2) has type char. If you really want to do that, you should do

printf("Port: %d",*(uint32_t*)(msg+2));

As noted by @R.., msg+2 almost certainly does not meet the right alignment requirements for type uint32_t. If the code appears to work, it's an accident and not portable.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • 1
    That's not valid code. `msg+2` almost certainly does not meet the right alignment requirements for type `uint32_t`; if the code appears to work, it's an accident and not portable. – R.. GitHub STOP HELPING ICE May 19 '12 at 00:05
2

This line

printf("Port: %d",*(msg+2));

prints the 'char' value at (msg+2) address, not the uint32_t !

Use

uint32_t PortFromProc = *(uint32_t*)(msg+2);
printf("Port: %d", PortFromProc);

To "fix" port numbers from recvfrom() function one must use the ntohl() function.

Viktor Latypov
  • 14,289
  • 3
  • 40
  • 55
  • Hi, this works. But when sending msg with sendto() (UDP) and receiving it with recvfrom uint32_t PortFromProc = *(uint32_t*)(msg+2); has a wrong value again. – user1324258 May 18 '12 at 20:50
  • 1
    The port numbers in recvfrom() are in big-endian format (highest byte goes first). Use ntohs/ntohl functions for the value recieved from recvfrom(). – Viktor Latypov May 18 '12 at 21:31
  • Dp you mean sth like this `uint32_t PortFromProc = htonl(*(uint32_t*)(msg+2));` ? – user1324258 May 18 '12 at 21:47
  • Yes. However, many people here including me would recommend you to avoid using these crazy type-casts with pointers. Split the code to multiple lines. This will help you to avoid the problems like the one in your code. – Viktor Latypov May 18 '12 at 21:52
  • I thought using ntohs/ntohl is only important for setting the port to sockaddr_in. When sending messages with sendto i have never used htonl. And when sending uint8_t with sendto, it works correctly, but why not with uint32_t? Sorry i forgot to say that i dont use recvfrom, but select(). – user1324258 May 18 '12 at 22:17
  • There is a convention that all socket functions accept port numbers in Big-Endian format (higher byte first), which is the exact opposite of the Little-Endian format used on Intel-based machines. If you do the send/recv(or send/bind) pair of operations on two different machines, you just make the "double fault" of inverting bytes and thus it seems like it's working. – Viktor Latypov May 20 '12 at 08:22