30

I'm using C and trying to get access to the constant M_PI (3.14159...). I have imported the math.h header file, but the M_PI constant was still undefined. Through some searching on StackOverflow I have found that I need to add #define _USE_MATH_DEFINES to my code (see example code below). This works fine when compiling normally, but I need to be able to compile with the std=c89 flag for the work that I'm doing.

How should I access M_PI from some C89 code?

robintw
  • 27,571
  • 51
  • 138
  • 205

4 Answers4

41

A conforming standard library file math.h is not only not required to, but actually must not define M_PI by default. In this context 'by default' means that M_PI must only get defined through compiler-specific tricks, most often undefined behavior through the use of reserved identifiers.

Just define the constant yourself (you can use the name M_PI freely, but should you want to be able to compile the code with a non-conforming compiler, you must first check that M_PI is not already defined). For convention's sake, do not define M_PI as anything other than (the approximation of) pi.

eq-
  • 9,986
  • 36
  • 38
  • 6
    @Jason S: it's simply a consequence of the fact that the standard library implementation is not allowed to "pollute" namespace (i.e. must only use reserved identifiers as per standard). – eq- Feb 16 '11 at 17:42
  • Is that so? That would mean a C implementation can never conform to C89 and C99 at the same time, since C99 adds identifiers to the library. – Fred Foo Mar 07 '12 at 11:11
  • 2
    @larsmans: C99 is careful to add identifiers that were reserved to the implementation in C89 (see in particular section 4.13 FUTURE LIBRARY DIRECTIONS in C89), or in new header files that were not defined in C89. However there are some corner cases of differing library behaviour between C89 and C99 - for example `strtod()` which must handle hexadecimal floating point in C99 and cannot in C89. – caf Mar 07 '12 at 11:27
  • 1
    @FredFoo That is correct; it is not possible to conform to C89 and C99 at the same time. That's why we have compiler switches to select one or the other. A C89 implementation can provide some C99 features as conforming extensions; the obvious situation is allowing the program to call C99 functions, or to use *long long* (as long as a diagnostic is emitted). – Kaz Sep 12 '18 at 22:14
31

I would go for

#ifndef M_PI
#    define M_PI 3.14159265358979323846
#endif
Sven Marnach
  • 574,206
  • 118
  • 941
  • 841
  • The fact that I would have to do something like that, instead of it just being guaranteed that PI is defined, makes me angry. – user16217248 Oct 25 '22 at 01:08
  • 1
    @user16217248 As you can see in the first answer, a conforming implementation actually _must not_ define `M_PI`, so it's kind of guaranteed it's not defined. I'd still go with the code in this answer, since there is no harm to checking whether it's already defined first. – Sven Marnach Oct 25 '22 at 07:09
  • @sven, It's actually the [third answer](/a/5008376/4850040) that says `M_PI` must not be defined by default. Perhaps that one was shown first for you, but remember that won't necessarily be the same for other readers (and it can change over time, depending on user settings). – Toby Speight Jan 18 '23 at 08:49
9

M_PI is not required by the C standard, it's just a common extension, so if you want to be standard you shouldn't rely on it. However, you can easily define your own #define for it, last time I checked it was a universal constant so there's not much space for confusion. :)

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
9

I fail to see what the problem is here; there is no incompatability between -std=c89 and _USE_MATH_DEFINES, one defines what language the compiler will compile, the other defines what parts of math.h get enabled.

Those parts that are enabled are not defined as part of the ISO C standard library, but that is not the same thing as not being standard C language, language and library are separate entities in C. It is no less C89 compliant than it would be if you had defined your own macros in your own header.

I would however suggest that you define the macro on the command-line rather than in the code:

-std=c89 -D_USE_MATH_DEFINES

If you ever encounter a math.h implementation that does not define M_PI, then that is easily fixed without code modification by similarly using command line defined macros:

-std=c89 -DM_PI=3.14159265358979323846
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • 1
    `_USE_*` is part of glibc internals, meant to be defined only be `features.h` as a result of some public feature-test macro being defined. Use `-D_GNU_SOURCE` or to be more portable, `-D_XOPEN_SOURCE=700` or similar. – R.. GitHub STOP HELPING ICE Jun 09 '13 at 23:07
  • @R..: It was the OP that determined to use the macro after finding it elsewhere on StackOverflow - he failed to specify where unfortunately. The [GNU documentation](http://www.gnu.org/software/libc/manual/html_node/Mathematical-Constants.html) says to define "`_BSD_SOURCE` or `_XOPEN_SOURCE=500`, or a more general feature select macro", while [Microsoft's C Runtime documentation](http://msdn.microsoft.com/en-us/library/4hwaceh6(v=vs.71).aspx) says to define `_USE_MATH_DEFINES`, so I'd stick with the latter just for compatibility; the question does not mention any specific compiler. – Clifford Jun 10 '13 at 12:16