views:

341

answers:

10

It goes without saying that using hard-coded, hex literal pointers is a disaster:

int *i = 0xDEADBEEF;
// god knows if that location is available

However, what exactly is the danger in using hex literals as variable values?

int i = 0xDEADBEEF;
// what can go wrong?

If these values are indeed "dangerous" due to their use in various debugging scenarios, then this means that even if I do not use these literals, any program that during runtime happens to stumble upon one of these values might crash.

Anyone care to explain the real dangers of using hex literals?


Edit: just to clarify, I am not referring to the general use of constants in source code. I am specifically talking about debug-scenario issues that might come up to the use of hex values, with the specific example of 0xDEADBEEF.

+3  A: 

A hex literal is no different than a decimal literal like 1. Any special significance of a value is due to the context of a particular program.

Steve Madsen
Not related to the question but... congrats on having exactly 1024 reputation. ;)
R. Bemrose
Didn't last long though...
Steve Madsen
+11  A: 

There's no more danger in using a hex literal than any other kind of literal.

If your debugging session ends up executing data as code without you intending it to, you're in a world of pain anyway.

Of course, there's the normal "magic value" vs "well-named constant" code smell/cleanliness issue, but that's not really the sort of danger I think you're talking about.

Jon Skeet
Jon, this might have been asked/answered elsewhere but why did you change your name to Tony the Pony?
graham.reeds
@Graham: http://meta.stackoverflow.com/questions/28192/has-jon-skeet-been-hacked
Jon Seigel
+1  A: 

I don't see any problem with using it as a value. Its just a number after all.

Daniel A. White
+5  A: 

With few exceptions, nothing is "constant".

We prefer to call them "slow variables" -- their value changes so slowly that we don't mind recompiling to change them.

However, we don't want to have many instances of 0x07 all through an application or a test script, where each instance has a different meaning.

We want to put a label on each constant that makes it totally unambiguous what it means.

if( x == 7 )

What does "7" mean in the above statement? Is it the same thing as

d = y / 7;

Is that the same meaning of "7"?

Test Cases are a slightly different problem. We don't need extensive, careful management of each instance of a numeric literal. Instead, we need documentation.

We can -- to an extent -- explain where "7" comes from by including a tiny bit of a hint in the code.

assertEquals( 7, someFunction(3,4), "Expected 7, see paragraph 7 of use case 7" );

A "constant" should be stated -- and named -- exactly once.

A "result" in a unit test isn't the same thing as a constant, and requires a little care in explaining where it came from.

S.Lott
I am not referring to the issue of using well-named constants. I am talking about the debug scenarios using said constants.
Yuval A
+2  A: 

There's no reason why you shouldn't assign 0xdeadbeef to a variable.

But woe betide the programmer who tries to assign decimal 3735928559, or octal 33653337357, or worst of all: binary 11011110101011011011111011101111.

NickFitz
+1  A: 

There's no danger in using a hard-coded hex value for a pointer (like your first example) in the right context. In particular, when doing very low-level hardware development, this is the way you access memory-mapped registers. (Though it's best to give them names with a #define, for example.) But at the application level you shouldn't ever need to do an assignment like that.

Ken Bloom
+2  A: 

I believe the concern raised in the IP address formatting question earlier today was not related to the use of hex literals in general, but the specific use of 0xDEADBEEF. At least, that's the way I read it.

There is a concern with using 0xDEADBEEF in particular, though in my opinion it is a small one. The problem is that many debuggers and runtime systems have already co-opted this particular value as a marker value to indicate unallocated heap, bad pointers on the stack, etc.

I don't recall off the top of my head just which debugging and runtime systems use this particular value, but I have seen it used this way several times over the years. If you are debugging in one of these environments, the existence of the 0xDEADBEEF constant in your code will be indistinguishable from the values in unallocated RAM or whatever, so at best you will not have as useful RAM dumps, and at worst you will get warnings from the debugger.

Anyhow, that's what I think the original commenter meant when he told you it was bad for "use in various debugging scenarios."

Ray Burns
+3  A: 

Big Endian or Little Endian?

One danger is when constants are assigned to an array or structure with different sized members; the endian-ness of the compiler or machine (including JVM vs CLR) will affect the ordering of the bytes.

This issue is true of non-constant values, too, of course.

Here's an, admittedly contrived, example. What is the value of buffer[0] after the last line?

const int TEST[] = { 0x01BADA55,  0xDEADBEEF };
char buffer[BUFSZ];

memcpy( buffer, (void*)TEST, sizeof(TEST));
NVRAM
A: 
int *i = 0xDEADBEEF;
// god knows if that location is available

int i = 0xDEADBEEF;
// what can go wrong?

The danger that I see is the same in both cases: you've created a flag value that has no immediate context. There's nothing about i in either case that will let me know 100, 1000 or 10000 lines that there is a potentially critical flag value associated with it. What you've planted is a landmine bug that, if I don't remember to check for it in every possible use, I could be faced with a terrible debugging problem. Every use of i will now have to look like this:

if (i != 0xDEADBEEF) { // Curse the original designer to oblivion
    // Actual useful work goes here
}

Repeat the above for all of the 7000 instances where you need to use i in your code.

Now, why is the above worse than this?

if (isIProperlyInitialized()) { // Which could just be a boolean
    // Actual useful work goes here
}

At a minimum, I can spot several critical issues:

  1. Spelling: I'm a terrible typist. How easily will you spot 0xDAEDBEEF in a code review? Or 0xDEADBEFF? On the other hand, I know that my compile will barf immediately on isIProperlyInitialised() (insert the obligatory s vs. z debate here).
  2. Exposure of meaning. Rather than trying to hide your flags in the code, you've intentionally created a method that the rest of the code can see.
  3. Opportunities for coupling. It's entirely possible that a pointer or reference is connected to a loosely defined cache. An initialization check could be overloaded to check first if the value is in cache, then to try to bring it back into cache and, if all that fails, return false.

In short, it's just as easy to write the code you really need as it is to create a mysterious magic value. The code-maintainer of the future (who quite likely will be you) will thank you.

Bob Cross
Again, not really what I was going for...
Yuval A
A: 

I use CAFEBABE I haven't seen it used by any debuggers before.

James