3
#include <iostream>

int main(){
    uint8_t memory[1024];
    memory[0] = 1;
    memory[1] = 1;
    uint32_t *test = memory;
    //is it possible to get a value for *test that would be in this example 257?
}

I want to create a uin32_t pointer to the same adress as the uint8_t pointer. Is this possible without using new(adress)? I don't want to lose the information at the adress. I know pointers are just adresses and therefor I should be able to just set the uint32_t pointer to the same adress.
This code produces an error:

invalid conversion from 'uint8_t*' to 'uint32_t*' in initialization
Croxa
  • 71
  • 1
  • 4

5 Answers5

5

This would be a violation of so-called Strict Aliasing Rule, so it can not be done. Sad, but true.

Use memcpy to copy data and in many cases compilers will optimize memory copy and generate the same code as they would with cast, but in Standard-conforming way.

acraig5075
  • 10,588
  • 3
  • 31
  • 50
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • Some compilers offer options to disable the strict aliasing rule, like -fno_strict_aliasing. (But in most cases it does not make sense to use them IMHO). – alain Jun 06 '18 at 14:26
  • @alain disabling this is often a terrible pessimization – SergeyA Jun 06 '18 at 14:28
  • Yes, I agree. The only use case I see is if you have a very large legacy code base that you're unwilling to change at the moment. – alain Jun 06 '18 at 14:30
4

As already mentioned you cannot convert uint8_t * to uint32_t * due to strict aliasing rule, you can convert uint32_t * to unsigned char * though:

#include <iostream>

int main(){
    uint32_t test[1024/4] = {}; // initialize it!
    auto memory = reinterpret_cast<unsigned char *>( test );
    memory[0] = 1;
    memory[1] = 1;
    std::cout << test[0] << std::endl;
}

this is not portable code due to Endianness, but at least it does not have UB.

Slava
  • 43,454
  • 1
  • 47
  • 90
  • You might as well explain why it is not portable (not evident for everyone, I suppose) – SergeyA Jun 06 '18 at 14:34
  • It could be noted that `uintxx_t` types *when they exist* are required to have exactly xx bits and **no padding bits**. So if that code is compiled, the result is implementation defined because of endianness, but no UB is involved and no trap representation is possible. Simply, an implementation is free to not define the `uintxx_t` types... – Serge Ballesta Jun 06 '18 at 15:19
0

This question completely ignores the concept of endian-ness; while your example has the lower and upper byte the same value, if the byte order is swapped it makes no difference; but in the case where it is; your number will be wrong unexpectedly.

As such, there's no portable way to use the resulting number.

UKMonkey
  • 6,941
  • 3
  • 21
  • 30
0

You can do that with union. As mentioned above, you have to be aware of endianness of target device, but in most cases it will be little-endian. And there is also a bit of controversy about using unions in such way, but fwiw it's getting a job done and for some uses it's good enough.

#include <iostream>

int main(){
    union {
        uint8_t memory[1024] = {};
        uint32_t test[1024/4];
    };
    
    memory[0] = 1;
    memory[1] = 1;
    std::cout << test[0]; // 257
}
Krzysiek
  • 2,494
  • 16
  • 20
-3
uint32_t *test =(uint32_t*) memory;

uint32_t shows that the memory pointed by test should contain uint32_t .

Vishnu R
  • 94
  • 5
  • This is even worse than `reinterpret_cast` which already explained why it is wrong to do it. – Slava Jun 06 '18 at 14:24