0
#include <fstream>
#include<iostream>
#include<cstring>
using namespace std;

class Address {
public:
    char addr[6];
    Address() {}
    Address(string address) {
        size_t pos = address.find(":");
        int id = stoi(address.substr(0, pos));
        short port = (short)stoi(address.substr(pos + 1, address.size()-pos-1));
        memcpy(addr, &id, sizeof(int));
        memcpy(&addr[4], &port, sizeof(short));
    }
};
enum MsgTypes{
    JOINREQ,
    JOINREPLY,
    DUMMYLASTMSGTYPE,
    HEARTBEAT
};

/**
 * STRUCT NAME: MessageHdr
 *
 * DESCRIPTION: Header and content of a message
 */
typedef struct MessageHdr {
    enum MsgTypes msgType;
}MessageHdr;

    typedef struct en_msg {
        // Number of bytes after the class
        int size;
        // Source node
        Address from;
        // Destination node
        Address to;
    }en_msg;

//class Testing{

void send(Address *myaddr, Address *toaddr, char *data, int size);
    int main()
    {
        MessageHdr *msg=new MessageHdr();
        size_t msgsize = sizeof(MessageHdr) + sizeof(Address) + sizeof(long) + 1;
        msg=(MessageHdr  *)malloc(msgsize*sizeof(char));
        int id=233;
        short  port =22;
        long heartbeat=1;
        msg=(MessageHdr  *)malloc(msgsize*sizeof(char));
        string s=to_string(id)+":"+to_string(port);
        string s1=to_string(id+1)+":"+to_string(port+1);
        cout<<s<<'\n';
        cout<<s1<<'\n';
        Address *addr= new Address(s);
        for (int i = 0; i < 6; i++)
            cout << addr->addr[i];

        Address *toaddr= new Address(s1);
        msg->msgType = JOINREQ;
        //cout<<(char *)msg->msgType;
        memcpy((char *)(msg+1), addr, sizeof(addr));
        memcpy((char *)(msg+1) + 1 + sizeof(addr), &heartbeat, sizeof(long));
        send(addr, toaddr, (char *)msg,  msgsize);
        return 0;
    }

        void send(Address *myaddr, Address *toaddr, char *data, int size) {
            cout<<"inside send"<<'\n';
        en_msg *em;
//static char temp[2048];

        em = (en_msg *)malloc(sizeof(en_msg) + size);
        em->size = size;

        memcpy(&(em->from), &(myaddr), sizeof(em->from));
        memcpy(&(em->to), &(toaddr), sizeof(em->from));
        memcpy(em + 1, data, size);
        cout<<(char *)(em+1);
    }

This is my program,in between I am trying to check the address what is being stored in my char array. but upon printing the array, it gives some strange output. two strange symbols after printing the value of s and s1. I am trying to store the id:port in the char array of the address class, but looks without success. Please help

The code I am referring to for printing is in the main function. Approx ten lines down the main function.

For say, my id is 233 and port is 22, The address is 233:22 I want to retrieve back 233:22 and print it. How do I do that here?

Thanks in advance :)

Bhavya Arora
  • 49
  • 1
  • 1
  • 7
  • 3
    Your memcpy's in Address are undefined behaviour, although it will probably work on little-endian systems. Don't mix C-style struct typedefs and C++ struct syntax, as it's confusing. Why do you allocate a `MessageHdr` with new, discard and leak it, allocate it again with malloc, discard and leak it, and then allocate it again? I think that's enough for now. – Neil Kirk Mar 20 '15 at 17:36
  • please use `endl` for `cout` new line – ha9u63a7 Mar 20 '15 at 17:37
  • 3
    @ha9u63ar Why? It's perfectly fine to use `\n` for `cout` and totally irrelevant to the many issues with the code. – Neil Kirk Mar 20 '15 at 17:37
  • The problem is I am trying to understand a code and trying to produce a similar smaller code from a huge code base, I cannot change typedef and things, however I'l allocate memory with malloc as you said. but how to get the output of char array here, gives me strange symbol. The problem is not solved – Bhavya Arora Mar 20 '15 at 17:38
  • 2
    Nobody *said* to use malloc!? – Neil Kirk Mar 20 '15 at 17:39
  • 1
    Yes, you are trying to print binary data as ASCII characters. It is liable to look like garbage. Change your cout to output hexadecimal instead. – jschultz410 Mar 20 '15 at 17:41
  • @NeilKirk Why are the memcpys in Address's constructor undefined behavior? – David G Mar 20 '15 at 17:42
  • @jschultz410 To output chars as integers, you need to cast. Eg `cout << static_cast(addr->addr[i]);` – Neil Kirk Mar 20 '15 at 17:43
  • @0x499602D2 If `id` is 1, what is the value of `addr[0]` after the memcpy, according to the standard? – Neil Kirk Mar 20 '15 at 17:43
  • @NeilKirk, Or use `+addr->addr[i]`. The cast is rather cluttery if being used a lot. – chris Mar 20 '15 at 17:45
  • Yeah, I was referring to how to make cout format a number in hex rather than decimal. With printf I'd do something like `printf("0x%02x ", (unsigned) addr->addr[i]);` I don't know the calls to make cout dance similarly. – jschultz410 Mar 20 '15 at 17:46
  • If you're intending on using C++11, you should not be using `cstring`, `malloc`, and `memcpy`. – Julian Mar 20 '15 at 17:51
  • @NeilKirk: I don't think the memcpy's are undefined behavior, which gives the compiler the right to blow up the world if it wants. Instead, the resulting contents of `addr` are platform specific. The first sizeof(int) bytes of `addr` will contain whatever the internal, platform specific format of `id`'s value is in that function. – jschultz410 Mar 20 '15 at 17:52
  • 2
    @NeilKirk I'm not sure where you're going with this. `int` is a trivially copyable type and thus can be stored in an array of `char`. The value `addr[0]` would probably depend on the endianness of the system but that doesn't mean it's UB. – David G Mar 20 '15 at 17:52
  • @0x499602D2 Hm I think you are right. – Neil Kirk Mar 20 '15 at 17:55
  • @0x499602D2 http://stackoverflow.com/questions/29173001/using-memcpy-to-copy-an-int-into-a-char-array-and-then-printing-its-members-und – Neil Kirk Mar 20 '15 at 18:02

2 Answers2

1

The problem is in this line:

cout << addr->addr[i];

Since addr->addr is an array of char, each element will be printed as the character it represents. If you'd rather print the integer value of each, simply cast it to int first.

cout << static_cast<int>(addr->addr[i]); // or old-fashioned: (int)addr->addr[i];
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

Given the following code:

for (int i = 0; i <= 6; i++)
            cout << addr->addr[i];

And given Address's constructor:

size_t pos = address.find(":");
int id = stoi(address.substr(0, pos));
short port = (short)stoi(address.substr(pos + 1, address.size()-pos-1));
memcpy(addr, &id, sizeof(int));
memcpy(&addr[4], &port, sizeof(short));

It's clear that you are printing the bytes that conform a number

addr->addr is a char array which contains two integer variables, one having two bytes (int) and the other having 2 bytes (short).

So, if the number is , lets say, 436, you are printing:

0xB4 0x01 0x00 0x00 
<crazy char> SOH NULL  NULL

You must understand what are you printing, or what you want to print in order to print it properly.

Note: The most popular setup is assumed here, which means:

  • Little Endian arquitecture
  • 4-byte int
  • 2-byte short

Update

How to get address and port back:

int address;
unsigned short port;
memset(&address, addr->addr, 4);
memset(&port, addr->addr+4, 2);
ichramm
  • 6,437
  • 19
  • 30
  • 1
    What is a "standard" architecture? Is it big or little endian? – Neil Kirk Mar 20 '15 at 17:40
  • yeah, I was assuming little endian and a compiler which has 4-byte int and 2-byte short – ichramm Mar 20 '15 at 17:41
  • 2
    You might want to state your real assumptions rather than inventing new standards. – Neil Kirk Mar 20 '15 at 17:41
  • @NeilKirk I'm inventing nothing, little endian is the standard in the x86 x86_x64 arquitecture, and most popular compilers (gcc,clang,visualc++) have 4-byte int and 2-byte short. I will replace "standard" with "popular" but, if you want to troll someone you should should try somewhere else. – ichramm Mar 20 '15 at 17:59
  • 1
    How do you know he or a future reader is not using a big endian architecture? This is a question and answer site and answers should be kept accurate. Is that trolling? – Neil Kirk Mar 20 '15 at 18:00
  • For say, my id is 233 and port is 22, The address is 233:22 I want to retrieve back 233:22 and print it. How do I do that here. – Bhavya Arora Mar 20 '15 at 18:03
  • this code seems more like C to me, using C casts too – paulm Mar 20 '15 at 18:27
  • @ichramm I believe the easiest way to print it like the way I asked would be Remove the for loop and cout << *(char *)(addr->addr); the *(char *) thing was the thing I was confused with. – Bhavya Arora Mar 21 '15 at 02:20
  • That's not going to work either, you are dumping two integral values to a char array (and char=byte), those values must convert them back to integer in order to print them. – ichramm Mar 24 '15 at 12:46