tags:

views:

393

answers:

9
int valueToWrite = 0xFFFFFFFF;
static char buffer2[256];
int* writePosition = (int* ) &buffer2[5];
*writePosition = valueToWrite;

//OR
* ((int*) &buffer2[10] ) = valueToWrite;

Now, I ask you guys which one do you find more readable. The 2 step technique involving a temporary variable or the one step technique?

Do not worry about optimization, they both optimize to the same thing, as you can see here. Just tell me which one is more readable for you.

or  DWORD PTR ?buffer2@?1??main@@9@4PADA+5, -1
or  DWORD PTR ?buffer2@?1??main@@9@4PADA+10, -1
+1  A: 

I find the second, shorter one easier to read.

I suspect, however, that this rather depends on whether you are the type of person that can easily 'get' pointers.

The type casting from char* to int* is a little awkward, though. I presume there is a good reason this needs to be done.

thomasrutter
+2  A: 

The first example is more readable purely on the basis that your brain doesn't have to decipher the pointer operations globed together.

This will reduce the time a developer looking at the code for the first time needs to understand what's actually going. In my experience this loosely correlates to reducing the probability of introducing new bugs.

Brian Gianforcaro
Bugs is related to line of code, not complexity of code.
CDR
+17  A: 
int* writePosition = (int* ) &buffer2[5]

Or

*((int*) &buffer2[10] ) = valueToWrite;

Are both incorrect because on some platforms access to unaligned values (+5 +10) may cost hundreds of CPU cycles and on some (like older ARM) it would cause an illegal operation.

The correct way is:

memcpy( buffer+5, &valueToWrite, sizeof(valueToWrite));

And it is more readable.

Artyom
However if you /know/ you're on a platform with cheap unaligned accesses, then the memcpy option is likely to be slower.
bdonlan
I've just tested memcpy and it optimizes to a single MOV, which is pretty good :)So yea, memcpy is a good solution too.
toto
+1  A: 

Watch out -- this code probably won't work due to alignment issues! Why not just use memset?

#include <string.h>
memset(buffer2+10, 0xFF, 4);
rlbond
You should use sizeof(int), rather than assuming int == 4 bytes
Todd Gardner
Sadly, I tested memset and VC++ did a very bad job at optimizing it. I won't show the asm code because there's a scary imul in it ;)VC++ did a simple mov with memcpy heh.
toto
Were you in release mode? Also keep in mind a mov takes many more clock cycles than a store operation.
rlbond
Memset appears to be a compiler intrinsic in my version of VC++..
Crashworks
+4  A: 

If I was forced to choose, I'd say 1. However, I'll note the code as presented is very C like either way; I'd shy away from either and re-examine the the problem. Here's a simple one that is more C++-y

const char * begin = static_cast<char*>(static_cast<void*>(&valueToWrite));
std::copy(begin, begin+sizeof(int), &buffer2[5]);
Todd Gardner
And I'm more used to C style casts. Nice use of const though, it's more verbose, the compiler must love you :)
toto
The dual-static-cast-of-pointers for typesafety is unfortunately very messy, certainly my least favorite thing about c++ casting. And if you think my compiler loves me, you haven't what I do with templates...
Todd Gardner
+1  A: 

If you can afford to tie yourself to a single compiler (or do preprocessor hacks around compatiblity issues), you can use a packed-structs option to get symbolic names for the values you're writing. For example, on GCC:

struct __attribute__ ((__packed__)) packed_struct
{
  char stuff_before[5]
  int some_value;
}

/* .... */

static char buffer2[256];
struct packed_struct *ps = buffer2;
ps->some_value = valueToWrite;

This has a number of advantages:

  • Your code more clearly reflects what you're doing, if you name your fields well.
  • Since the compiler knows if the platform you're on supports efficient unaligned access, it can automatically choose between native unaligned access, or appropriate workarounds on platforms that don't support unaligned access.

But again, has the major disadvantage of not having any standardized syntax.

bdonlan
Interesting technique bdonlan. I am not a user of GCC but that's pretty impressive. It probably doesn't work with an offset determined at runtime though.
toto
Nope. But I believe (not /entirely/ sure) you can create a simple wrapper packed struct around just the int to get unaligned accesses portable across platforms supported by GCC.
bdonlan
+8  A: 

Once you encapsulate it inside a class, it does not really matter which technique you use. The method name will provide the description as to what the code is doing. Thus, in most cases you will not have to delve into the actual impl. to see what is going on.

class Buffer
{
    char buffer2[256];
public:
    void write(int pos, int value) { 
       int* writePosition = (int*) &buffer2[pos];
       *writePosition = value;
    }
}
Itay
Nice idea indeed!Good C++ intuition here.
toto
A: 

Most readable would be either variant with a comment added on what you're doing there.

That being said, I despise variables introduced simply for the purpose of a one-time use a couple of lines later. Doing most of my work in the maintenance area, getting dozens of variable names pushed in my face that are poor efforts not having to write an explanatory comment sets me on edge.

DevSolar
A: 

Definitely:

* ((int*) &buffer2[10] ) = valueToWrite;

I parse it not in one but few steps, and that is why it is more readable: I have all steps in one line.