tags:

views:

534

answers:

5
union LowLevelNumber
{
 unsigned int n;
 struct
 {
  unsigned int lowByte : 8;
  unsigned int highByte : 8;
  unsigned int upperLowByte : 8;
  unsigned int upperHighByte : 8;
 } bytes;
 struct
 {
  unsigned int lowWord : 16;
  unsigned int highWord : 16;
 } words;     
};

This union allows me to access the unsigned integer byte or word-wise. However, the code looks rather ugly:

var.words.lowWord = 0x66;

Is there a way which would allow me to write code like this:

var.lowWord = 0x66;

Update:
This is really about writing short / beautiful code as in the example above. The union solution itself does work, I just don't want to write .words or .bytes everytime I access lowWord or lowByte.

A: 

You could easily wrap that in a class and use get/set accessors.

John Gietzen
this makes code equally "bloated" and is not better than using a union
SDD
It would allow you to implement something that's actually portable without breaking the interface, and I don't see how it'd be more bloated.
jalf
bloated in the sense i outlined in my question: i want to ommit the accessors (.words, .bytes in this case)
SDD
it would omit the accessors.You cauld have a GetHighWord function directly in your class.
John Gietzen
yes, but I was asking for a way to write something like var.lowWord = 0x66;
SDD
+2  A: 

C++

Would http://www.cplusplus.com/reference/stl/bitset/ serve for your needs?

Plain C version would look something like this:

int32 foo;

//...

//Set to 0x66 at the low byte
foo &= 0xffffff00;
foo |= 0x66;

This is probably going to be more maintainable down the road than writing a custom class/union, because it follows the typical C idiom.

Paul Nathan
I don't see why this is an improvement to the union above
SDD
It's an improvement because the next guy to read your code(or you in 2 years) isn't going to scratch his head wondering what in the world is going on, and have to hunt around for the union code...oh...and your code might brutally fail on a 64-bit machine, too.
Paul Nathan
I'd even say that foo.LowByte = 0x66 is more readable than your code. It will only fail on 64 bit machine if the compiler model is not LLP.
SDD
The 64 bit issue can easily be solved via a #define
SDD
Ah, so your solution requires fiddlyness to make work in the future. My solution won't, plus it is C idiom. Best of luck.
Paul Nathan
what I said above is not correct - the union will only fail for an architecture which has a different endianess, because in case of 64 bit integers, the higher bits just aren't affected by the union.For a different endianess though it will fail and so will your solution.
SDD
+6  A: 
union LowLevelNumber {
    unsigned int n;
    struct {
        unsigned int lowByte : 8;
        unsigned int highByte : 8;
        unsigned int upperLowByte : 8;
        unsigned int upperHighByte : 8;
    };
    struct {
        unsigned int lowWord : 16;
        unsigned int highWord : 16;
    };
};

Note the removed bytes and words names.

Michael Krelin - hacker
it's as easy as that - thanks :)
SDD
You're welcome. It's not that I mind property emulation approach, but I didn't expect you to fall for one given the question you asked and the answers you've been given. ;-)I have the feeling someone will come and suggest that you use java instead ;-)
Michael Krelin - hacker
I think you should use Java instead.
John Gietzen
Nice try, but I'm afraid after behrooz' answer you're a bit late ;-)
Michael Krelin - hacker
+2  A: 

You can make

short& loword() { return (short&)(*(void*)&m_source); }

and use it if you don't care parenthesis.

Or you can go fancy

public class lowordaccess
{
   unsigned int m_source;
public:
   void assign(unsigned int& source) { m_source = source; }
   short& operator=(short& value) { ... set m_source }
   operator short() { return m_source & 0xFF; }
}

and then

struct LowLevelNumber
{
   LowLevelNumber() { loword.assign(number); }

   unsigned int number;
   lowordaccess loword;
}
var.loword = 1;
short n = var.loword;

The latter technique is a known property emulation in C++.

queen3
I really like your approach! very nice
SDD
While I appreciate this, and the code that I present is kind of cool and can be useful in other situations, I didn't really test it, and I personally think that hacker's approach is much more simplier and fits better with the very problem.
queen3
queen3
And by the way you could just do "{ MyNumberCtor() { loword = *(short*)((char*) } short }" i.e. have reference field named loword. You don't really need go fancy ;-)
queen3
Although I upvoted the last comment and find it generally useful (along with this whole answer, which I also upvoted), I really doubt introducing this overhead having 32 bits of data would make sense. Just think of what overhead would it be in case of 64-bit address space ;-)
Michael Krelin - hacker
Sometimes simplicity matters more than performance. I generally do not start optimizing until proven - it's always easier to make readable program optimized than to make optimized program readable. And after all, I simply did not know that one could just omit the struct name to get the desired result ;-)
queen3
And I think one can go fancy with C++ templates to achieve the same result as my "property" class - modern C++ compilers do heavy optimization, I'm not even sure that they'll keep your "convinient" as the class baggage in the final object code.
queen3
Although even your lack of knowledge about anonymous member I find almost positive, since it boosts creativity, I disagree with your view of optimizations. You, indeed, don't have to *optimize* before you have to, but it is important to try to write optimal code from the very start. And yes, it may be possible to do it with no compiled overhead, but source code overhead also impacts performance. Programmer's performance and code maintainability.
Michael Krelin - hacker
A: 

Using a union for this is bad, because it is not portable w.r.t. endianness.

Use accessor functions and implement them with bit masks and shifts.

starblue
true, but how would you write one class which would work with both types of endianess?
SDD
Implement them with bit masks and shifts. That works independently of endianness.
starblue
yeah but youo still need to have #defines in order to differentiate between big / little endianess. I don't see why I couldn't also do this with a union
SDD
starblue
The question is, though, whether it's correct to refer to the *most significant* word as a *high word* ;-) And that makes me doubt if you can talk about endianness breakage at all here. It depends on what do you expect it to return. Depending on that you may safely say that what *you* do breaks with different endianness.
Michael Krelin - hacker
I bow to your wisdom, starblue. That's a perfect argument you've made here.
Michael Krelin - hacker