2

This question is not the same as either of these:

I am running Windows 7 and Visual Studio Express 2012, but I expect neither to influence the answer to this question.

tl;dr How would I most appropriately counteract/prevent/tolerate the effects of the following excerpt from math.h, while still being allowed to compile with Visual C++?

#if     !__STDC__

/* Non-ANSI names for compatibility */

#define DOMAIN      _DOMAIN
#define SING        _SING
#define OVERFLOW    _OVERFLOW
#define UNDERFLOW   _UNDERFLOW
#define TLOSS       _TLOSS
#define PLOSS       _PLOSS

#define matherr     _matherr

Background: I'm writing a hobby text-based C++ project whose overall goals are far outside this question's scope. I'm using GNU Make (for familiarity and portability) to compile it with both Cygwin g++ and cl.exe, and assuming a strictly standards-compliant environment... so far. I'm beginning to think that Windows simply doesn't allow such an assumption.

I have an enum whose members include OVERFLOW and UNDERFLOW. The problem described below threatens to force me to change those names, but I would prefer to keep them because they are most appropriate for my purpose, notwithstanding outside influences such as Windows header files.

GCC, Visual C++, and Mac OS X's header files (independent of llvm-gcc) all define OVERFLOW and UNDERFLOW, among other non-standard macros, in math.h by default.

  • GCC has a selection of documented means of cleanly preventing those definitions.
  • Mac OS X has a couple of undocumented means to do the same, one of which (_POSIX_C_SOURCE) coincides with GCC's documentation. (I mention this in the interest of compensating for Apple's lack of documentation; I have a history with these identifiers.)
  • MSDN documents the /u command-line option as a means (via the __STDC__ macro) of preventing the definition of a few non-standard macros in Visual C++. As shown at the beginning of this question, the __STDC__ macro also prevents definition of OVERFLOW and UNDERFLOW.

Upon discovering that the /u switch would prevent the definitions I was concerned with, I added it to my makefile. But then I got a new error from line 44 of crtdefs.h:

error C1189: Only Win32 target supported!

This is because _WIN32 is no longer defined. A bit of searching indicated that crtdefs.h is related to the Windows Driver Development Kit. I'm not developing a driver; can I somehow not use that header? Or do I just need to rename my enum members to tolerate non-standard Windows behavior?

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Grault
  • 974
  • 12
  • 31
  • Did I hear that right - C++/CLI? As in Common Language Infrastructure, AKA .NET? Abandon your quest for standard compliance. CLI is as much Microsoft extension as could be. – Seva Alekseyev Sep 18 '12 at 02:36
  • 2
    @Seva CLI = Command-Line Interface – Grault Sep 18 '12 at 02:48
  • Microsoft compiler strictly not-Ansi and not-ISO standard. Also C99 no supported, so this is moot. You can use minGW or clang as as a compliant ones. There is more to it than definitions. A number of features is absent, a number of ill-formed code cases is allowed. The system is supporting several call conventions at same time, so it's really messy. – Swift - Friday Pie Mar 23 '23 at 03:51

3 Answers3

2

Instead of using the /u compiler switch, which has multiple effects, just use /D__STDC__=1 which causes the __STDC__ macro to be defined, and nothing else.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • >.< I shoulda thought of that. I unconsciously interpreted that page as indicating they were effectively synonymous. That fixed the issue; many thanks. – Grault Sep 18 '12 at 04:31
1

Two possibilities spring to mind.

The first is to make sure you reverse the specific effects whenever you include math.h, with something like:

#include <math.h>
#undef OVERFLOW
#undef UNDERFLOW

Now, that may also cause problems down the track somewhere with code that expects those things to be defined properly. However, even in that case, you could modify your software to use a different name for the math.h ones:

#include <math.h>
#undef OVERFLOW
#undef UNDERFLOW
#define MATH_H_OVERFLOW  _OVERFLOW
#define MATH_H_UNDERFLOW _UNDERFLOW

You'd just have to ensure that all source code (already-compiled code like libraries won't matter) that wants to use the math.h ones, uses the MATH_H_* constants instead of the ones in your enumeration.


The second is to think very carefully about the amount of effort you're putting into this quest, as compared to the amount of effort it would take to simply rename your enum members to something that doesn't conflict. Something like using Overflow for your enumeration (instead of OVERFLOW) would be my first attempt since there's still exactly the same amount of information in both, and it removes the immediate conflict.

Yes, I know it would be nice to find a way that doesn't involve that, but you should be in the business of delivering software rather than spending inordinate amounts of time working around minor nitpicks with your environment :-)

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Regarding #1, I forgot to mention that I'm concerned that's not very clean... I prefer to prevent rather than counteract if possible. But that's what I'll probably do unless I encounter a reason not to. (I never use the math.h macros.) – Grault Sep 18 '12 at 02:51
  • And re: #2... Yeah, but I'm stubborn and this is for future reference. I figure I'll run into this kind of thing later so I might as well deal with it now. – Grault Sep 18 '12 at 02:52
  • @Jesdisciple, #1 _will_ actually prevent it, simply because the standard dictates pre-processor phase happens before "proper" compilation (including creation of an enumeration). At the time when you define the enumeration, or _use_ those symbols, they won't exist as `#define` values. That's not going to help if you have some source code that relies on the math.h values but that can be fixed by using either `MATH_H_*` constants instead, or renaming your enum fields. – paxdiablo Sep 18 '12 at 02:59
0

In C++11 you can use scoped enums:

enum class Flows { Underflow, Overflow };

You now refer to Flows::Underflow and Flows::Overflow.

Even in C++98 it's good practice use simulate this with classes:

class Flows
{
public:
    enum Value { Underflow, Overflow };
};
user1610015
  • 6,561
  • 2
  • 15
  • 18
  • I scope them in a namespace; the preprocessor doesn't care and puts the values 3 and 4 where the identifiers were. – Grault Sep 18 '12 at 03:32
  • +1 / @Jesdisciple: you're missing a key point here... this solution uses mixed case identifiers, not uppercase. Apart from the single-uppercase-character and single-character+number identifiers commonly used for template parameters, all-uppercase identifiers should be left for preprocessor macros. You should be using mixed case or lower-case - subtle pros and cons to each but either would prevent clashes. – Tony Delroy Sep 18 '12 at 03:52
  • @TonyDelroy I suppose I am tainted by other languages; I associate all-caps with the semantics of constants, which roughly speaking are met by both macros and compile-time constants (such as enum members). I also generally detest macros (type-unsafe and basically part of a separate language) and would prefer to expunge as many non-standard ones from my environment as possible even apart from this issue. – Grault Sep 18 '12 at 04:09
  • @Jesdisciple: understandable... it's intuitively nice to have such notations but all the Hungarian-notation-like tradeoffs exist - discredited a decade or more ago. Personally, I tend to use mixed case for abstractions that don't occupt memory - like class names and enumeration identifiers, and lower case for variables, but as constants can be enums or variables it's at best ugly to change identifiers if you switch type just to maintain that "encoding", at worst impractical if clients are already coupled: suggest all non-macro constants should be lower case. (camelCase: apply to first letter) – Tony Delroy Sep 18 '12 at 04:56
  • @TonyDelroy I'm not sure what Hungarian has to do with this but I would be interested in how it was discredited. Upper and lower camelCase are already my norm for classes and everything else, respectively. I feel like I'm losing information if I deny constants a separate set of identifiers. – Grault Sep 19 '12 at 05:18
  • Worth reading "disadvantages" and "notable opinions" from http://en.wikipedia.org/wiki/Hungarian_notation - the issues are the same for consts, but people strike their own compromises - I use an underscore suffix on member data, and a p_ prefix on pointers... subtle differences from type encoding (e.g. Pointers imply semantics around access to a type that probably do need to be revisited if moving to say a reference, where as polymorphism et al allow types sharing semantics to be substituted transparently). – Tony Delroy Sep 19 '12 at 13:11