Created
March 27, 2010 13:27
-
-
Save DanielG/346045 to your computer and use it in GitHub Desktop.
Print any type as binary with automatic endian swap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "PrintBinary.h" | |
int main () | |
{ | |
printBinary(float_sign_mask, kPB_GROUP); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <stdarg.h> | |
#include <stdint.h> | |
enum printBinary_opt | |
{ | |
kPB_NO_OPT = 0, | |
kPB_LITTLE_ENDIAN = 1, | |
kPB_BIG_ENDIAN = (1 << 1), | |
kPB_GROUP = (1 << 2), | |
}; | |
void printBinaryByte(uint8_t byte); | |
template <typename T> | |
void printBinary(T var, int flags = kPB_NO_OPT); | |
/// \brief Storage for a byte swap sequence, providing swapping methodes | |
/// The ByteSwapSequence class provides storage for the sequence to swap | |
/// the bytes of variables passed to it's methodes in. | |
template <typename T> | |
class ByteSwapSequence | |
{ | |
public: | |
typedef std::vector<size_t> BOrder; | |
ByteSwapSequence() { for(uint8_t i=0; i < sizeof(T) ;++i) { swappingSequences.push_back(i); } } | |
ByteSwapSequence(BOrder swappingSeqs) { swappingSequences = swappingSeqs; } | |
ByteSwapSequence(uint8_t size, ...) | |
{ | |
va_list argptr; | |
va_start( argptr, size ); | |
for(uint8_t i=0; i < size ;++i) | |
{ | |
swappingSequences.push_back(va_arg( argptr, uint8_t )); | |
} | |
va_end( argptr ); | |
} | |
T networkToHost(const T networkVar) | |
{ | |
assert(swappingSequences.size() == sizeof(T)); | |
const uint8_t* cNet = reinterpret_cast<const uint8_t*> (&networkVar); | |
uint8_t* swapped = new uint8_t[sizeof(T)]; | |
for(uint8_t i=0; i < sizeof(T) ;++i) | |
{ | |
swapped[swappingSequences[i]] = cNet[i]; | |
} | |
return *reinterpret_cast<T*> (swapped); | |
} | |
T hostToNetwork(const T hostVar) | |
{ | |
assert(swappingSequences.size() == sizeof(T)); | |
const uint8_t* cHost = reinterpret_cast<const uint8_t*> (&hostVar); | |
uint8_t* swapped = new uint8_t[sizeof(T)]; | |
for(uint8_t i=0; i < sizeof(T) ;++i) | |
{ | |
std::cout << "cHost: " << cHost[swappingSequences[i]] << std::endl; | |
swapped[i] = cHost[swappingSequences[i]]; | |
} | |
return *reinterpret_cast<T*> (swapped); | |
} | |
void Print() | |
{ | |
for(int i=0; i < swappingSequences.size() ;++i) | |
{ | |
std::cout << (int)swappingSequences[i] << " "; | |
} | |
std::cout << std::endl; | |
} | |
static ByteSwapSequence<T> getBigEndianSwap() | |
{ | |
BOrder seq; | |
for(int i=sizeof(T)-1; i != -1 ;--i) { seq.push_back(i); } | |
return ByteSwapSequence(seq); | |
} | |
static ByteSwapSequence<T> getLittleEndianSwap() | |
{ | |
BOrder seq; | |
for(uint8_t i=0; i < sizeof(T) ;++i) { seq.push_back(i); } | |
return ByteSwapSequence(seq); | |
} | |
private: | |
BOrder swappingSequences; | |
}; | |
/// \brief Check for byte swap sequence to get to a predefined byte order <REWORD> | |
/// Given a constant with known byteorder, now called "network byte order", this | |
/// function finds out how the bytes of check have to be swapped to make it equal | |
/// to constant, to order the bytes in network byte order. | |
/// \param[in] constant A constante with a known byte order | |
/// \param[in] check A variable or constant with unknown byte order | |
/// \return The sequence in which the bytes of check have to be swapped to make it | |
/// the same byte order as constant, contained in a ByteSwapSequence class | |
template <typename T> | |
ByteSwapSequence<T> findSwapSequence(const T constant, const T check) | |
{ | |
// If the numbers already match we dont have to do anything, yey :-) | |
if(constant == check) | |
return ByteSwapSequence<T>(); | |
const uint8_t* cCheck = reinterpret_cast<const uint8_t*> (&check); | |
typename ByteSwapSequence<T>::BOrder byteNumberArray; | |
for(size_t i=0; i < sizeof(T) ;++i) { byteNumberArray.push_back(i); } | |
// Permutate the byte order until constant and check match | |
do | |
{ | |
uint8_t* checkCopy = new uint8_t[sizeof(T)]; | |
memcpy((void*)checkCopy, (void*)&check, sizeof(T)); | |
for(size_t i=0; i < byteNumberArray.size() ;++i) | |
{ | |
checkCopy[i] = cCheck[byteNumberArray[i]]; | |
} | |
delete[] checkCopy; | |
if(constant == *reinterpret_cast<T*> (checkCopy)) | |
return ByteSwapSequence<T>(byteNumberArray); | |
} while(next_permutation(byteNumberArray.begin(), byteNumberArray.end())); | |
return ByteSwapSequence<T>(); | |
} | |
template<typename T> | |
ByteSwapSequence<T> autoDetectSwapSequence() | |
{ | |
// A known big endian value is written into magicBigEndian | |
T magicBigEndian = 0; | |
for(uint8_t i=0; i < sizeof(T) ;++i) | |
{ | |
reinterpret_cast<uint8_t*>(magicBigEndian)[i] = i; | |
} | |
// A platform dependent integral constant is written into nativeNumber | |
/// TODO: Check if this works on other platforms | |
T nativeNumber = 66051; | |
// If the platform is not BigEndian nativeNumber is going to be different from | |
// magicBigEndian. Next swap the byte order as long as the numbers dont match | |
ByteSwapSequence<T> swapper = findSwapSequence(magicBigEndian, nativeNumber); | |
return swapper; | |
} | |
/// \brief Print var as binary, pass options to customize output | |
/// \param[in] var The variable to be printed as binary | |
/// \param[in] flags Or'ed flags from printBinary_opt | |
template <typename T> | |
void printBinary(T var, int flags = kPB_NO_OPT) | |
{ | |
T swapped_var = var; | |
if(!(flags & kPB_BIG_ENDIAN || flags & kPB_LITTLE_ENDIAN)) | |
{ | |
swapped_var = autoDetectSwapSequence<T>().networkToHost(var); | |
} | |
else | |
{ | |
if(flags & kPB_BIG_ENDIAN) | |
{ | |
swapped_var = | |
ByteSwapSequence<T>::getBigEndianSwap().networkToHost(var); | |
} | |
else if(flags & kPB_LITTLE_ENDIAN) | |
{ | |
swapped_var = | |
ByteSwapSequence<T>::getLittleEndianSwap().networkToHost(var); | |
} | |
} | |
uint8_t* var_ptr = reinterpret_cast<uint8_t*>(&swapped_var); | |
for (unsigned int iByte=0; iByte < sizeof(T) ;++iByte) | |
{ | |
printBinaryByte(var_ptr[iByte]); | |
if(flags & kPB_GROUP) std::cout << " "; | |
} | |
std::cout << std::endl; | |
} | |
/// \brief print the bits in a byte | |
void printBinaryByte(uint8_t byte) | |
{ | |
uint8_t mask = 128; | |
for(uint8_t iBit=0; iBit < 8 ;++iBit) | |
{ | |
if(mask & byte) | |
std::cout << "1"; | |
else | |
std::cout << "0"; | |
if(mask == 1) | |
mask = 128; | |
else | |
mask = mask >> 1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment