patterncppMinor
Split a long integer into eight 4-bit values
Viewed 0 times
bitintolongsplitvalueseightinteger
Problem
It's an exercise from a book. There is a given long integer that I should convert into 8 4-bit values. The exercise is not very clear for me, but I think I understood the task correctly.
I googled how to return with an array in a function. In the splitter function I add the last 4 bits into the values array, then cut the them from the original number.
Is this a good way to do this?
I googled how to return with an array in a function. In the splitter function I add the last 4 bits into the values array, then cut the them from the original number.
Is this a good way to do this?
#include
int * splitter(long int number)
{
static int values[8];
for (int i = 0; i > 4);
}
return values;
}
int main()
{
long int number = 432214123;
int *values;
values = splitter(number);
for (int i = 7; i >= 0; i--)
std::cout << values[i] << " ";
return 0;
}Solution
There are only three issues I take with your code...
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
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.
- 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(number & 0XF)) instead of the C style casting (e.g.(int)(number & 0xF)).
- You should use
std::int32_tinstead oflongorstd::uint32_tinstead ofunsigned long.longis 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
#include
#include
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
#include
#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;
}Code Snippets
#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;
}#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;
}Context
StackExchange Code Review Q#30593, answer score: 6
Revisions (0)
No revisions yet.