Eric Sosman
6/3/2011 11:48:00 AM
On 6/3/2011 7:02 AM, John Small wrote:
> I have been trying to resurrect some old code. Since the last time the
> code compiled correctly one the 3rd party header files has changed in
> a way that prevents the old code from compiling.
>
> The changed 3rd party header file now uses a typedef to define an
> enumeration type. And two of the names used for the enumeration
> constants that typedef now match names used in #defines's in the old
> code. But the values of the names in the enueration type do not match
> the values set be the #define's in the old code.
>
> Unfortunately the conflict occurs with identifiers that are used in
> many places in 50+ source files. So I am hoping that I don't have to
> change the identifiers in the old code's defines and all the
> references to these identifiers.
>
> Changing the 3rd party header is not an option. And using the new
> values for the names is not an option either because the old code used
> its #define's to name specific numbers.
>
> Is there a way to tell the compiler to use my #define of XYZ over the
> enumeration constant XYZ?
Wherever the macro is visible, the compiler will *always* use
it -- so the answer to your first question is "Yes, and you're
already doing it." :)
You don't mention the nature of the compilation problem, but
I'm going to guess it's something like
/* your code */
#define XYZ "forty-two"
#include "foreign.h"
...
/* foreign.h */
enum frobozz { ABC, XYZ };
...
.... and the compiler chokes because your macro definition turns
the header's content into the equivalent of
enum frobozz { ABC, "forty-two" };
.... which is a syntax error. If this is the case, one possible
approach would be to postpone defining the macro until after the
inclusion:
#include "foreign.h" /* declares XYZ as an enum constant */
#define XYZ "forty-two" /* doesn't interfere with the enum */
Now, since all pre-existing uses of XYZ in your own code were meant
to expand to "forty-two" anyhow (you never used the enum constant
before the constant even existed), your code will compile just as it
did before. The enum constant XYZ will languish, still declared but
inaccessible.
Unfortunately, this might not work. The foreign header might
go on to use XYZ in other ways:
/* foreign.h */
enum frobozz { ABC, XYZ };
void foreignWorker(enum frobozz, const char *plugh);
#define FOREIGN_YES(x) foreignWorker(ABC, (x))
#define FOREIGN_MAYBE(x) foreignWorker(XYZ, (x))
.... and now when your code uses
FOREIGN_MAYBE("Say it ain't so, Joe!");
.... which used to work with the old version's FOREIGN_MAYBE, you
wind up with the equivalent of
foreignWorker("forty-two", "Say it ain't so, Joe!");
.... and just get a different compilation error. (The particular
use shown here is just an example; similar problems would arise
any time foreign.h defines a macro with XYZ in its expansion, and
when your code invokes the macro you get the wrong XYZ.)
Besides, even if rearranging the order of inclusion cures the
problem for the moment, the solution is fragile and likely to
come unstuck eventually. Inclusion order is not too difficult to
set up initially, but is quite difficult to maintain as new
headers are invented, old headers are combined, and code evolves.
I'd recommend that you go through your existing code, changing
all XYZ to MY_XYZ. Yes, it's scut-work, but you'll only have to
do it once (unless you're unlucky in your choice of a new name...).
Half a hundred files won't take very long; it's not as if you were
dealing with an enormous code base. If you've still got the old
third-party header and libraries available, build your renamed code
with them and run your existing tests before incorporating the
newer version; it'll be a useful confidence-builder to know that
your renaming has not gone awry somewhere.
--
Eric Sosman
esosman@ieee-dot-org.invalid