The curse of the redefinition of the symbol HLOG


A customer was running into a compiler error complaining about redefinition of the symbol HLOG.

#include <pdh.h>
#include <lm.h>

...

The result is

lmerrlog.h(80): error C2373: 'HLOG' redefinition; different type modifiers
pdh.h(70): See declaration of 'HLOG'

"Our project uses both performance counters (pdh.h) and networking (lm.h). What can we do to avoid this conflict?"

We've seen this before. The conflict arises from two problems.

First is hubris/lack of creativity. "My component does logging. I need a handle to a log. I will call it HLOG because (1) I can't think of a better name, and/or (2) obviously I'm the only person who does logging. (Anybody else who wants to do logging should just quit their job now because it's been done.)"

This wouldn't normally be a problem except that Win32 uses a global namespace. This is necessary for annoying reasons:

  • Not all Win32 languages support namespaces.
  • Even though C++ supports namespaces, different C++ implementations decorate differently, so there is no agreement on the external linkage. (Indeed, the decoration can change from one version of the C++ compiler to another!)

Fortunately, in the case of HLOG, the two teams noticed the collision and came to some sort of understanding. If you include them in the order

#include <lm.h>
#include <pdh.h>

then pdh.h detects that lm.h has already been included and avoids the conflicting definition.

#ifndef _LMHLOGDEFINED_
typedef PDH_HLOG     HLOG;
#endif

The PDH log is always accessible via the name PDH_HLOG. If lm.h was not also included, then the PDH log is also accessible under the name HLOG.

Sorry for the confusion.

Comments (6)
  1. kantos says:

    true different compilers mangle differently, however there is no need to worry about mangling here (for C++)

    #ifdef _LMHLOGDEFINED_

    namespace pdh

    {

      using HLOG = PDH_HLOG;

    }

    #endif

    This creates a namespaced alias and is the syntax used by the C++ standard library to define functions from the C standard library into the C++ standard library. Because this is only a naming alias it doesn't have the same side effects as actually using a namespaced version.

    [But the underlying problem (the "true" type is in the global namespace) still remains. -Raymond]
  2. Rangi says:

    And with a little bit more thought, they could have called it PDH_HLOG in the first place, and avoid conflict with any future HLOG definitions. Naming everything with a prefix like "PDH_" *is* the usual way to imitate namespaces in C, right?

    [See "hubris/lack of creativity". -Raymond]
  3. anonymouscommenter says:

    My memory is hazy, but I ran into a problem with a system function named "Log" once may years ago. On OpenVMS I think. The company I used to work for included an internal diagnostic logging library in its driver products. The library was written in C and statically linked. I remember having to delve into the linker manual to resolve the clash between the system function and our unfortunately named diagnostic "Log" function. If I recall correctly, OpenVMS (at the time) didn't care about case sensitivity when linking, so maybe it was the C runtime logarithm function that was the problem. Strangely enough, I was reminded of this the other day when the "Make sure the function you're calling is the right one" article came out.

  4. Brian_EE says:

    Ok, so I'm pretty much a digital hardware engineer though I do write some software for small jobs and/or hardware debugging... Even I know how to dig into header files when resolving a compiler issue. Didn't it occur them to *actually open the files* and look at the definitions themselves?

    Then again, I remember about 15 years ago digging through an embedded C++ design to find and point out to our software engineer the source of a null-pointer de-referencing bug to prove that my FPGA design was not the cause of spontaneous radio reboots.

    I wonder why engineers are so unwilling (or unable) to do basic problem solving when the compiler basically points them to the error (including file names and line numbers).

  5. anonymouscommenter says:

    Modularity in the language (namespaces) helps impose modularity in the design, but design itself can mitigate these issues.  Wrap the Lan Manager functions and expose your wrapper.  Do the same for the Perf Counter functions.  Code that needs lm.h never needs to see pdh.h, and vice-versa.

    If it is required that all header files be visible to all translation units (using stdafx.h), there are 1,967 header files in the latest SDK... 2 files that do not satifisy the ordering constraint == 99.9% correct.  A tremendous achievement by Microsoft engineers, especially considering the rate that new features are added, that must remain compatible with cruft from the past.

  6. anonymouscommenter says:

    Would it be possible for pdh.h to define a symbol and lm.h to use a #error directive to give an error message saying what the correct order to import the libraries is?

    OTOH a mechanism like that would probably be overkill.

Comments are closed.

Skip to main content