There are only three issues I take with your code...
- The caller of the splitter function has the possibility of trying to access a value outside of the returned array and could cause a memory access violation if they did so. For this reason alone, it would be better to go with the vector approach that @Jamal posted.
- You should use the C++ style casting (e.g.
static_cast<int>(number & 0XF)
) instead of the C style casting (e.g. (int)(number & 0xF)
).
- You should use
std::int32_t
instead of long
or std::uint32_t
instead of unsigned long
. long
is not gauranteed to be 32 bits, especially on 64 bit platforms. I don't take as big of an issue with this as some do though because on most systems, it will be at least 32 bits.
Here is a solution that only returns one nybble at a time and throws an exception if the caller tries to access an invalid portion of the of number. Since your book hasn't talked about pointers or vectors yet, this might actually be the type of approach it is looking for (possibly minus the exception throwing if it hasn't talked about exceptions yet either). If you take away the exception throwing, the caller still cannot cause a memory access violation though. If they passed something lower than 0 or greater than 7 as the value of part
they would just get a return value of 0
.
#include <iostream>
#include <stdexcept>
#include <cstdint>
unsigned short get_nybble( std::uint32_t number, const unsigned short part )
{
if( part > 7 )
throw std::out_of_range("'part' must be a number between 0 and 7");
return (number >> (4 * part)) & 0xF;
}
int main( int argc, char* argv[] )
{
std::uint32_t number = 432214123;
try {
for( short i = 7; i >= 0; i-- )
std::cout << get_nybble(number, i) << " ";
} catch( std::exception& ex ) {
std::cerr << "Error: " << ex.what() << std::endl;
}
return 0;
}
This may not be the best solution, but another approach I find interesting is an anonymous union combined with a bit field struct. This works with the GNU G++ compiler and should also work with Visual C++. Note that as I understand it this is potentially unsafe on non x86 systems due to the structure packing which I'd bet your book has not talked about yet either.
#include <iostream>
#include <cstdint>
#pragma pack(push, 1)
typedef union
{
std::uint32_t value;
struct
{
std::uint32_t part1: 4;
std::uint32_t part2: 4;
std::uint32_t part3: 4;
std::uint32_t part4: 4;
std::uint32_t part5: 4;
std::uint32_t part6: 4;
std::uint32_t part7: 4;
std::uint32_t part8: 4;
};
} nybbles;
#pragma pack(pop)
int main( int argc, char* argv[] )
{
nybbles num;
num.value = 432214123;
std::cout << "Parts = "
<< num.part8 << ", "
<< num.part7 << ", "
<< num.part6 << ", "
<< num.part5 << ", "
<< num.part4 << ", "
<< num.part3 << ", "
<< num.part2 << ", "
<< num.part1 << std::endl;
return 0;
}