-2

I am trying to convert a char array to integers:

const int LENGTH = 3 * sizeof(int);
char data[LENGTH];

/* data is filled */

for (int i = 0; i < LENGTH; i += sizeof(int)) {
    std::cout << "Integer: " << (int)data[i] << std::endl;
}

for (int i = 0; i < LENGTH; i += sizeof(short)) {
    std::cout << (short)data[i] << "   ";
}

the output is:

Integer: 0
Integer: 0
Integer: 0
0  3  0  3  0  3

I'd expect that if the shorts are not zero so must the integers. Probably the conversion as seen here works for just that one character/byte and not as expected for the folloing 4 bytes. How can I fix that?

To be clear: I want bytes 0 to 3 casted into one integer, then the next (4 to 7) into the next integer and so on...

MrJonas
  • 197
  • 11
  • 1
    `/* data is filled */` where? how? with what? – underscore_d Dec 14 '17 at 15:35
  • integers send via network connection from android, but that should not make a difference because the shorts proof that there is some data in the data[]. – MrJonas Dec 14 '17 at 15:37
  • You can convert a char to an int, so that's easy, however, how do you expect to cast the char to an int? Adding the char values together to form an int? Or make the int bits = to the 3 char bits (would result in a different value than the addition of the chars)? – peti446 Dec 14 '17 at 15:43
  • @peti446 With what they were trying to do, it would just be a simple arithmetic promotion, keeping the same value but widening the type. However, it seems that what they really want is a reinterpretation through pointers, so using pointer casts instead of arithmetic ones. – underscore_d Dec 14 '17 at 15:55

2 Answers2

0

As @underscore_d pointed out, *((int*)&data[i]) from this answer will result in undefined behaviour and memcpy should be used.

int intData[3];
std::memcpy(intData, data, sizeof data);

for (int i = 0; i < 3; i++) {
    std::cout << "int: " << intData[i] << "   ";
}

is working fine and complies with the reference of memcpy.

MrJonas
  • 197
  • 11
  • 3
    And that violates the aliasing rules, so your program has undefined behaviour. Ideally you would instead declare an array of the destination type, `int`, and then `memcpy()` the bytes from the network into that. So, when you finally read them as `int`, there's really a `int` alive there, rather than just some `char`s that you want the compiler to treat as `int`s. This assumes, as Darhuuk said, you will have the right endianness to do so; if you don't, then you need to read and convert manually. – underscore_d Dec 14 '17 at 15:54
  • 1
    @underscore_d Thanks for pointing out that it is undefined behaviour! I have used `std::memcpy` to copy the data from the `char[]` to an `int[]`. That is the actual example from the [memcpy-reference](http://en.cppreference.com/w/cpp/string/byte/memcpy). – MrJonas Dec 15 '17 at 13:43
0

You are casting data[i] to an int. However, data[i] is a char, so you can cast all you want, the cast is not going to magically read extra bytes. Instead, you have to cast the data pointer to int * and only then dereference it.

Basically, you'll end up with something like this:

auto voidPtr = static_cast<void const *>(data);
auto intPtr = static_cast<int const *>(voidPtr);

for (size_t i = 0; i < LENGTH / sizeof(int); ++i) {
  std::cout << "Int: " << intPtr[i] << "\n";
}

Note how i is only incremented by 1 each time, but the number of increments is divided by sizeof(int). This is because the compiler will automatically do the right thing when you're indexing an int *.

Also be aware that what you're getting back might not be what you expect. Depending on whether the machine you're running this on is big- or little-endian.

P.S.: It's generally discouraged to use a C-style cast, static_cast<int> is much more explicit in showing what you want to achieve.

AVH
  • 11,349
  • 4
  • 34
  • 43