HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Split a long integer into eight 4-bit values

Submitted by: @import:stackexchange-codereview··
0
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?

#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...

  • 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_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 
#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.