Obfuscated C++
- By Rob Murray
- March 22, 2000
Last Month's Obfuscated C++
Last month we asked you to explain the semantics of function f in the following code:
static void
g(unsigned long x) {
if (!x) throw 0;
if (x&1) {
try {g(x>>1);} catch (int x) {
throw x+1;
}
}
g(x>>1);
}
int
f(unsigned long l) {
try {
g(l);
} catch (int l) {
return l;
}
return 6;
}
f returns the number of 1-bits in its argument. The actual count is implemented by function
g, which always throws its result instead of returning it. The first line of
g throws a
0 if the input is
0. Otherwise, the low bit is tested. If it is
1, we recursively call
g on
x>>1, catch the result, increment it, and rethrow it. (Note that the
x in "
throw x+1" refers to the caught value, not the argument to
g.) If the low bit is
0 we simply call
g(x>>1) but do not catch the result.
The calls will recurse down until all of the 1-bits have been shifted off. At that point, an integer 0 will be thrown from the innermost function. That integer will be caught at each level of the call stack that corresponds to a 1-bit, incremented, and rethrown. The final value returned from the top-level g will be the number of 1-bits in the original argument.
The "return 6" in f is a red herring. That code is never executed, since g always exits with a throw.
This Month's Obfuscated C++
Identify the error in the following file:
static char* saved = 0;
void saveString(const char* cp) {
delete saved;
saved = new char[strlen(cp)]+1;
strcpy(saved,cp);
}
char* getString() {
if(!saved) return 0;
char* rc = new char[strlen(saved)]+1;
strcpy(rc,saved);
return rc;
}
Rob Murray is Director of Operations at the Irvine office of Nuforia, an object-oriented software consulting company based in Houston, TX. He has taught C++ at technical conferences since 1987 and is the author of C++ Strategies and Tactics. He was the founding editor of C++ Report and may be contacted at [email protected].
|