3

I have a value of type UINT8 and I would like to make it UINT32.

Would my following code be considered correct, valid, efficient and safe?

UINT32 convU8toU32(UINT8 *number) {
  UINT32 result = *number;
  return *result;
}

Please notice that I'm a new comer to C++ from the Java world.

Jason C
  • 38,729
  • 14
  • 126
  • 182
M. A. Kishawy
  • 5,001
  • 11
  • 47
  • 72
  • 4
    Now your code is "correct" (until the `return *result;` which should be `return result;`), but why using a pointer instead of a simple `UINT8`? – Holt Oct 11 '16 at 13:14
  • @Holt No reason, I'm experimenting with the language. I thought that would be more efficient with the memory usage. – M. A. Kishawy Oct 11 '16 at 13:18
  • 1
    @M.A.Kishawy If you are concerned about memory usage, don't replace an 8 bit integer with a 32/64 bit pointer. ;) But one usually need not worry about those amounts of memory "wasted" anyways. – Baum mit Augen Oct 11 '16 at 13:20
  • 2
    @M.A.Kishawy The compiler is a much better code generator than you are. Don't think about "memory usage", especially here. Most likely that parameter will end up in a register anyways (or the compiler may just inline it, and if it's really smart it may even just make it a no-op once it looks at how the caller is using it). Plus, on a PC at least, you have gigabytes of memory. – Jason C Oct 11 '16 at 13:23
  • It's impossible to say without making assumptions. What are the definitions of `UINT8` and `UINT32`? – Pete Becker Oct 11 '16 at 13:23
  • 2
    @PeteBecker Built-in unsigned integer types with a width of 8 and 32 bits respectively I was bold enough to assume. If that was wrong, please correct me OP. – Baum mit Augen Oct 11 '16 at 13:25
  • 1
    @PeteBecker An 8-bit and 32-bit unsigned int, respectively, because we assume a sane world free of conspiracies to trick us. In any case go big or go home, I say: Either don't ask that question, or go all the way and ask things like "Is `return` `#define`d to something goofy somewhere? Please show us the preprocessor output." :P – Jason C Oct 11 '16 at 13:26
  • 2
    @JasonC - there is nothing more perverse than the real world. Engineering should be based on knowledge, not unstated assumptions. – Pete Becker Oct 11 '16 at 13:29
  • 1
    @PeteBecker I don't know. I think some folks' perception of reality can certainly exceed reality's perverseness sometimes... we could always migrate this question to http://skeptics.stackexchange.com/ though. :D – Jason C Oct 11 '16 at 13:34
  • I just hope you don't fall in the common pointer trap when switching from Java to C++. Unlike Java modern C++ should use (almost) never `new`. – AliciaBytes Oct 11 '16 at 14:17

4 Answers4

7

The function is correct as is (the typo with the * in the return *result; aside), but you don't even need it. Integers (and other integral types) convert implicitly to one another, and as UINT32 can represent every value a UINT8 can have, you can simply write

UINT32 target = source;

for some UINT8 source.

Making the conversion explicit with a static_cast is optional; if the conversion was (potentially) narrowing, the cast would silence some compiler warnings.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
4

You need

 UINT32 result = static_cast<UINT32>(*number);

to de-refernce the pointer and cast it to the right type

But would

UINT32 convU8toU32(UINT8 number) {
   return static_cast<UINT32>(number);
}

be better and avoid pointers in the first place

Event better avoid the function call and type in the static cast in the appropriate line of code.

Ed Heal
  • 59,252
  • 17
  • 87
  • 127
  • 3
    You don't actually need `static_cast` here. For widening casts it is identical to the implicit cast and just adds verbosity. You may *want* it if you're in to strict C++ philosophical correctness (nothing wrong with that, although I personally dislike the verbosity especially compared to equivalent C style casts) but you do not *need* it. The original assignment with the implicit cast is sufficient and correct. – Jason C Oct 11 '16 at 13:18
  • 1
    *"implicit cast"* s/cast/conversion/, casts are always explicit. – Baum mit Augen Oct 11 '16 at 13:23
  • 1
    And there I was thinking that "modern" C++ encourages redundant verbosity :) – dtech Oct 11 '16 at 13:28
  • @ddriver C++: [Yo dawg](http://knowyourmeme.com/memes/xzibit-yo-dawg), I heard you like templates... – Jason C Oct 11 '16 at 13:32
4
UINT32 convU8toU32(UINT8 *number) {
  UINT32 result = *number;
  return *result;
}

I assume in my answer that UINT32 and UINT8 are fancy aliases for fundamental integer types.

Would my [...] code be considered

  • correct, valid

No, given my assumption that UINT32 is an integer. You cannot dereference an integer. Which is what you try to do on line return *result;

  • efficient

Does not matter since it is not correct.

  • safe

Well, it safely fails to compile.


This should be OK:

UINT32 convU8toU32(UINT8 number) {
    return number;
}

Of course, this is so simple that you may want to consider not calling the function, but assign directly in the first place:

// not UINT32 foo = convU8toU32(some_uint8);
// but instead:
UINT32 foo = some_uint8;
Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
3

Well, no. Assuming UINT32 is a 32-bit unsigned integral type and UINT8 is an 8-bit unsigned integral type, your code

UINT32 convU8toU32(UINT8 *number) {
   UINT32 result = *number;
   return *result;
}

would not even compile. The reason is that an integral type cannot be dereferenced as if it is a pointer. The statement return *result will therefore not compile, let alone be executed.

In reality, converting an 8-bit unsigned integral value to a 32-bit unsigned integral type is perfectly simple.

UINT32 convU8toU32(UINT8 number)
{
   UINT32 result = number;
   return result;
}

or, even more simply,

UINT32 convU8toU32(UINT8 number)
{
   return number;
}

These rely on implicit conversions to 32-bit unsigned integral type. Since a 32-bit unsigned integral type can exactly represent every value that an 8-bit unsigned integral type can, the conversion preserves value. Conversion the other way (from 32-bit to 8-bit) potentially loses value.

If you want to avoid implicit conversions, simply do an explicit conversion, such as

UINT32 convU8toU32(UINT8 number)
{
    return (UINT32) number;    // C-style conversion - discouraged in C++
}

or

UINT32 convU8toU32(UINT8 number)
{
    return UINT32(number);
}

or (to really make it obvious to anyone looking, and easy to find when searching a source file)

UINT32 convU8toU32(UINT8 number)
{
    return static_cast<UINT32>(number);
}

Of course, a function isn't even needed

 UINT8 value8 = something();
 UINT32 value32 = value8;

will do instead of using this function.

Peter
  • 35,646
  • 4
  • 32
  • 74