最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - Math error conditions (C99, C11, etc.) in GCC - Stack Overflow

programmeradmin1浏览0评论

With ISO C99 onward we have a few macros (or constants) that help understanding how some math errors (see <math.h> related) are signaled. However, to me it looks like they haven't been implemented in GCC yet.

Take the file "me.c" as in

#include  <math.h>
#include  <stdio.h>
#include  <errno.h>

int main(void)
{
    if (math_errhandling & MATH_ERRNO)
    {
        if (errno == EDOM)
        {
            fprintf(stderr, "Domain error!\n");
        }
    }
    return  0;
}

I compile it with MinGW64 (GCC 14.2.0) as follows

gcc  -std=c11 -Wall -Wextra -O2 -lm me.c -o me.exe
me.c: In function 'main':
me.c:7:9: error: 'math_errhandling' undeclared (first use in this function)
    7 |     if (math_errhandling & MATH_ERRNO)
      |         ^~~~~~~~~~~~~~~~
me.c:7:9: note: each undeclared identifier is reported only once for each function it appears in
me.c:7:28: error: 'MATH_ERRNO' undeclared (first use in this function)
    7 |     if (math_errhandling & MATH_ERRNO)
      |                            ^~~~~~~~~~

The same code compiled with Clang (19.1.3) shows no error

clang   -std=c11 -Wall -Wextra -O2 me.c -o me.exe

Am I missing anything in GCC invocation?

With ISO C99 onward we have a few macros (or constants) that help understanding how some math errors (see <math.h> related) are signaled. However, to me it looks like they haven't been implemented in GCC yet.

Take the file "me.c" as in

#include  <math.h>
#include  <stdio.h>
#include  <errno.h>

int main(void)
{
    if (math_errhandling & MATH_ERRNO)
    {
        if (errno == EDOM)
        {
            fprintf(stderr, "Domain error!\n");
        }
    }
    return  0;
}

I compile it with MinGW64 (GCC 14.2.0) as follows

gcc  -std=c11 -Wall -Wextra -O2 -lm me.c -o me.exe
me.c: In function 'main':
me.c:7:9: error: 'math_errhandling' undeclared (first use in this function)
    7 |     if (math_errhandling & MATH_ERRNO)
      |         ^~~~~~~~~~~~~~~~
me.c:7:9: note: each undeclared identifier is reported only once for each function it appears in
me.c:7:28: error: 'MATH_ERRNO' undeclared (first use in this function)
    7 |     if (math_errhandling & MATH_ERRNO)
      |                            ^~~~~~~~~~

The same code compiled with Clang (19.1.3) shows no error

clang   -std=c11 -Wall -Wextra -O2 me.c -o me.exe

Am I missing anything in GCC invocation?

Share Improve this question asked Nov 20, 2024 at 8:56 LuCLuC 4133 silver badges13 bronze badges 7
  • MSVC does compile the given code. – Weather Vane Commented Nov 20, 2024 at 9:06
  • Similarly here: on macOS with Homebrew-installed gcc 14.2, it compiles fine. So it's something specific for your GCC setup, I'm afraid. If things are undeclared, could that indicate math.h isn't what it appears to be (e.g., an empty file like a placeholder)? – 9769953 Commented Nov 20, 2024 at 9:07
  • 2 This looks like it might be a platform thing. – user2357112 Commented Nov 20, 2024 at 9:09
  • @9769953 <math.h> is indeed correct: here I cut code to be short, but I can use successfully any feature of <math.h> – LuC Commented Nov 20, 2024 at 9:15
  • @user2357112 Now that's very interesting. Have no clue why those remain undefined on the mentioned platform – LuC Commented Nov 20, 2024 at 9:19
 |  Show 2 more comments

1 Answer 1

Reset to default 1

This concerns [CPPReference]: MATH_ERRNO, MATH_ERREXCEPT, math_errhandling.

I'm going to exemplify on [SO]: math_errhandling undeclared in C (Windows 10 OS) (@CristiFati's answer).

Outpute:

  • Ubuntu 20 pc064:

    [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackExchange/StackOverflow/q075000209]> ~/sopr.sh
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [064bit prompt]> ls
    main00.c  main_win_pc064_vs19.exe
    [064bit prompt]>
    [064bit prompt]> # ---------- GCC ----------
    [064bit prompt]> gcc --version | grep gcc
    gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
    [064bit prompt]> gcc -fPIC -o main_linux_pc064_gcc main00.c -lm
    [064bit prompt]>
    [064bit prompt]> ./main_linux_pc064_gcc
    MATH_ERRNO: 0x00000001
    MATH_ERREXCEPT: 0x00000002
    math_errhandling: 0x00000003
    FE_ALL_EXCEPT: 0x0000003D
    EDOM: 0x00000021
    
    Done.
    
    [064bit prompt]>
    [064bit prompt]> # ---------- CLang ----------
    [064bit prompt]> clang --version | grep version
    clang version 10.0.0-4ubuntu1
    [064bit prompt]> clang -fPIC -o main_linux_pc064_clang main00.c -lm
    [064bit prompt]>
    [064bit prompt]> ./main_linux_pc064_clang
    MATH_ERRNO: 0x00000001
    MATH_ERREXCEPT: 0x00000002
    math_errhandling: 0x00000003
    FE_ALL_EXCEPT: 0x0000003D
    EDOM: 0x00000021
    
    Done.
    
    [064bit prompt]>
    [064bit prompt]> # ---------- MinGW64 GCC ----------
    [064bit prompt]> x86_64-w64-mingw32-gcc --version | grep gcc
    x86_64-w64-mingw32-gcc (GCC) 9.3-win32 20200320
    [064bit prompt]> x86_64-w64-mingw32-gcc -fPIC -o main_win_pc064_linuxmgw64gcc main00.c -lm
    main00.c: In function ‘main’:
    main00.c:8:36: error: ‘MATH_ERRNO’ undeclared (first use in this function)
        8 |     printf("MATH_ERRNO: 0x%08X\n", MATH_ERRNO);
          |                                    ^~~~~~~~~~
    main00.c:8:36: note: each undeclared identifier is reported only once for each function it appears in
    main00.c:9:40: error: ‘MATH_ERREXCEPT’ undeclared (first use in this function)
        9 |     printf("MATH_ERREXCEPT: 0x%08X\n", MATH_ERREXCEPT);
          |                                        ^~~~~~~~~~~~~~
    main00.c:10:42: error: ‘math_errhandling’ undeclared (first use in this function)
       10 |     printf("math_errhandling: 0x%08X\n", math_errhandling);
          |                                          ^~~~~~~~~~~~~~~~
    [064bit prompt]>
    
  • Cygwin pc064:

    [cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackExchange/StackOverflow/q075000209]> ~/sopr.sh
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [064bit prompt]> ls
    main00.c  main_linux_pc064_clang  main_linux_pc064_gcc  main_win_pc064_vs19.exe
    [064bit prompt]>
    [064bit prompt]> # ---------- GCC ----------
    [064bit prompt]> gcc --version | grep gcc
    gcc (GCC) 12.4.0
    [064bit prompt]> gcc -fPIC -o main_cyg_pc064_gcc main00.c -lm
    [064bit prompt]>
    [064bit prompt]> ./main_cyg_pc064_gcc
    MATH_ERRNO: 0x00000001
    MATH_ERREXCEPT: 0x00000002
    math_errhandling: 0x00000003
    FE_ALL_EXCEPT: 0x0000003D
    EDOM: 0x00000021
    
    Done.
    
    [064bit prompt]>
    [064bit prompt]> # ---------- MinGW64 GCC ----------
    [064bit prompt]> x86_64-w64-mingw32-gcc --version | grep gcc
    x86_64-w64-mingw32-gcc (GCC) 12.4.0
    [064bit prompt]> x86_64-w64-mingw32-gcc -fPIC -o main_cyg_pc064_mgw64gcc main00.c -lm
    main00.c: In function ‘main’:
    main00.c:8:36: error: ‘MATH_ERRNO’ undeclared (first use in this function)
        8 |     printf("MATH_ERRNO: 0x%08X\n", MATH_ERRNO);
          |                                    ^~~~~~~~~~
    main00.c:8:36: note: each undeclared identifier is reported only once for each function it appears in
    main00.c:9:40: error: ‘MATH_ERREXCEPT’ undeclared (first use in this function)
        9 |     printf("MATH_ERREXCEPT: 0x%08X\n", MATH_ERREXCEPT);
          |                                        ^~~~~~~~~~~~~~
    main00.c:10:42: error: ‘math_errhandling’ undeclared (first use in this function)
       10 |     printf("math_errhandling: 0x%08X\n", math_errhandling);
          |                                          ^~~~~~~~~~~~~~~~
    [064bit prompt]>
    [064bit prompt]> # ---------- MinGW32 GCC ----------
    [064bit prompt]> i686-w64-mingw32-gcc --version | grep gcc
    i686-w64-mingw32-gcc (GCC) 12.4.0
    [064bit prompt]> i686-w64-mingw32-gcc -fPIC -o main_cyg_pc064_mgw32gcc main00.c -lm
    main00.c: In function ‘main’:
    main00.c:8:36: error: ‘MATH_ERRNO’ undeclared (first use in this function)
        8 |     printf("MATH_ERRNO: 0x%08X\n", MATH_ERRNO);
          |                                    ^~~~~~~~~~
    main00.c:8:36: note: each undeclared identifier is reported only once for each function it appears in
    main00.c:9:40: error: ‘MATH_ERREXCEPT’ undeclared (first use in this function)
        9 |     printf("MATH_ERREXCEPT: 0x%08X\n", MATH_ERREXCEPT);
          |                                        ^~~~~~~~~~~~~~
    main00.c:10:42: error: ‘math_errhandling’ undeclared (first use in this function)
       10 |     printf("math_errhandling: 0x%08X\n", math_errhandling);
          |                                          ^~~~~~~~~~~~~~~~
    [064bit prompt]>
    
  • Win pc064 (same Cmd window as in the other answer):

    [prompt]> dir /b
    main00.c
    main_cyg_pc064_gcc.exe
    main_linux_pc064_clang
    main_linux_pc064_gcc
    main_win_pc064_vs19.exe
    
    [prompt]> gcc
    'gcc' is not recognized as an internal or external command,
    operable program or batch file.
    
    [prompt]>
    [prompt]> :: ---------- MinGW64 GCC ----------
    [prompt]> set PATH=%PATH%;f:\Install\Qt\Qt\Tools\mingw730_64\bin
    
    [prompt]> gcc --version | findstr gcc
    gcc (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0
    
    [prompt]> gcc -fPIC -o main_win_pc064_mgw64gcc main00.c -lm
    main00.c: In function 'main':
    main00.c:8:36: error: 'MATH_ERRNO' undeclared (first use in this function); did you mean '_INC_ERRNO'?
         printf("MATH_ERRNO: 0x%08X\n", MATH_ERRNO);
                                        ^~~~~~~~~~
                                        _INC_ERRNO
    main00.c:8:36: note: each undeclared identifier is reported only once for each function it appears in
    main00.c:9:40: error: 'MATH_ERREXCEPT' undeclared (first use in this function); did you mean 'MATH_ERRNO'?
         printf("MATH_ERREXCEPT: 0x%08X\n", MATH_ERREXCEPT);
                                            ^~~~~~~~~~~~~~
                                            MATH_ERRNO
    main00.c:10:42: error: 'math_errhandling' undeclared (first use in this function)
         printf("math_errhandling: 0x%08X\n", math_errhandling);
                                              ^~~~~~~~~~~~~~~~
    
    [prompt]>
    

Different OSes, flavors, compilers, versions, the behavior seems consistent: MinGW64 GCC's math.h doesn't define the macros.

Looked a bit online and found these articles mentioning the same error:

  • [SourceFe]: [Mingw-w64-public] Constants for math function error handling not defined

  • [SourceFe]: Mingw-64 Prevent and Detect domain and range errors in math functions which states:

    I was able to find a solution. It turns out that you have to compile with the flag -fsignaling-nans.

    I tried that but with no success. Maybe the flag is for building MinGW itself?

  • [SourceFe]: Missing C99 <math.h> math_errhandling etc. (recently submitted by @IanAbbott - probably as an effect of this very question)

Also did some math.h (e.g.: [GitHub]: mirror/mingw-w64 - (v12.0.0) mingw-w64-headers/crt/math.h) comparisons, and it appears that the macros aren't defined in the ones belonging to MinGW.

Looks like it's a dead end.



Update #0

I took things a bit further and did a behavioral comparison (same compilers as in the linked answer).

main00.c:

#include <errno.h>
#include <fenv.h>
#include <float.h>
#include <math.h>
#include <stdio.h>

#define PRINT_MACRO(MACRO) printf(#MACRO ": 0x%08X\n", (MACRO))


int main()
{
    volatile double _one = -1.0;
    volatile double zero = 0.0;
    volatile double one = 1.0;

    double d;
    float f = FLT_MAX;

    PRINT_MACRO(FE_DIVBYZERO);
    PRINT_MACRO(FE_INEXACT);
    PRINT_MACRO(FE_INVALID);
    PRINT_MACRO(FE_OVERFLOW);
    PRINT_MACRO(FE_UNDERFLOW);
    PRINT_MACRO(FE_ALL_EXCEPT);

    errno = 0;
    feclearexcept(FE_ALL_EXCEPT);
    d = one / zero;
    printf("\n1 / 0: %.3lf\nerrno: %d\nfetestexcept(FE_ALL_EXCEPT): 0x%08X\n", d, errno, fetestexcept(FE_ALL_EXCEPT));

    errno = 0;
    feclearexcept(FE_ALL_EXCEPT);
    d = log2(_one);
    printf("\nlog2(-1): %.3lf\nerrno: %d\nfetestexcept(FE_ALL_EXCEPT): 0x%08X\n", d, errno, fetestexcept(FE_ALL_EXCEPT));

    errno = 0;
    feclearexcept(FE_ALL_EXCEPT);
    f *= 2;
    printf("\nFLT_MAX * 2: %.3f\nerrno: %d\nfetestexcept(FE_ALL_EXCEPT): 0x%08X\n", f, errno, fetestexcept(FE_ALL_EXCEPT));

    printf("\nDone.\n\n");
    return 0;
}

Output:

  • Ubuntu 20 pc064

    [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackExchange/StackOverflow/q079206440]> ~/sopr.sh
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [064bit prompt]> ls
    main00.c  math.h
    [064bit prompt]>
    [064bit prompt]> # ---------- GCC ----------
    [064bit prompt]> gcc -fPIC -o main_linux_pc064_gcc main00.c -lm
    [064bit prompt]>
    [064bit prompt]> ./main_linux_pc064_gcc
    FE_DIVBYZERO: 0x00000004
    FE_INEXACT: 0x00000020
    FE_INVALID: 0x00000001
    FE_OVERFLOW: 0x00000008
    FE_UNDERFLOW: 0x00000010
    FE_ALL_EXCEPT: 0x0000003D
    
    1 / 0: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000004
    
    log2(-1): -nan
    errno: 33
    fetestexcept(FE_ALL_EXCEPT): 0x00000001
    
    FLT_MAX * 2: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000028
    
    Done.
    
    [064bit prompt]>
    [064bit prompt]> # ---------- CLang ----------
    [064bit prompt]> clang -fPIC -o main_linux_pc064_clang main00.c -lm
    [064bit prompt]>
    [064bit prompt]> ./main_linux_pc064_clang
    FE_DIVBYZERO: 0x00000004
    FE_INEXACT: 0x00000020
    FE_INVALID: 0x00000001
    FE_OVERFLOW: 0x00000008
    FE_UNDERFLOW: 0x00000010
    FE_ALL_EXCEPT: 0x0000003D
    
    1 / 0: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000004
    
    log2(-1): -nan
    errno: 33
    fetestexcept(FE_ALL_EXCEPT): 0x00000001
    
    FLT_MAX * 2: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000028
    
    Done.
    
    [064bit prompt]>
    [064bit prompt]> # ---------- MinGW64 GCC (compile only) ----------
    [064bit prompt]> x86_64-w64-mingw32-gcc -fPIC -o main_win_pc064_linuxmgw64gcc main00.c -lm
    [064bit prompt]>
    
  • Win pc064:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079206440]> sopr.bat
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [prompt]> dir /b
    main00.c
    main_linux_pc064_clang
    main_linux_pc064_gcc
    main_win_pc064_linuxmgw64gcc.exe
    math.h
    
    [prompt]>
    [prompt]> :: ---------- VS2019 ----------
    [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul
    
    [prompt]> cl /nologo /MD /W0 main00.c  /link /NOLOGO /OUT:main_win_pc064_vs19.exe
    main00.c
    
    [prompt]>
    [prompt]> main_win_pc064_vs19.exe
    FE_DIVBYZERO: 0x00000008
    FE_INEXACT: 0x00000001
    FE_INVALID: 0x00000010
    FE_OVERFLOW: 0x00000004
    FE_UNDERFLOW: 0x00000002
    FE_ALL_EXCEPT: 0x0000001F
    
    1 / 0: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000008
    
    log2(-1): -nan(ind)
    errno: 33
    fetestexcept(FE_ALL_EXCEPT): 0x00000010
    
    FLT_MAX * 2: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000005
    
    Done.
    
    
    [prompt]>
    [prompt]> :: ---------- MinGW64 GCC ----------
    [prompt]> set PATH=%PATH%;f:\Install\Qt\Qt\Tools\mingw730_64\bin
    
    [prompt]> gcc -fPIC -o main_win_pc064_mgw64gcc main00.c
    
    [prompt]>
    [prompt]> main_win_pc064_mgw64gcc
    FE_DIVBYZERO: 0x00000004
    FE_INEXACT: 0x00000020
    FE_INVALID: 0x00000001
    FE_OVERFLOW: 0x00000008
    FE_UNDERFLOW: 0x00000010
    FE_ALL_EXCEPT: 0x0000003F
    
    1 / 0: 1.#IO
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000004
    
    log2(-1): -1.#IO
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000001
    
    FLT_MAX * 2: 1.#IO
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000028
    
    Done.
    
    
    [prompt]>
    [prompt]> :: ---------- Linux MinGW64 GCC (run only) ----------
    [prompt]> main_win_pc064_linuxmgw64gcc
    FE_DIVBYZERO: 0x00000004
    FE_INEXACT: 0x00000020
    FE_INVALID: 0x00000001
    FE_OVERFLOW: 0x00000008
    FE_UNDERFLOW: 0x00000010
    FE_ALL_EXCEPT: 0x0000003F
    
    1 / 0: 1.#IO
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000004
    
    log2(-1): -1.#IO
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000001
    
    FLT_MAX * 2: 1.#IO
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000028
    
    Done.
    
  • Cygwin pc064:

    [cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackExchange/StackOverflow/q079206440]> ~/sopr.sh
    ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
    
    [064bit prompt]> ls
    main00.c    main_linux_pc064_clang  main_win_pc064_linuxmgw64gcc.exe  main_win_pc064_vs19.exe
    main00.obj  main_linux_pc064_gcc    main_win_pc064_mgw64gcc.exe       math.h
    [064bit prompt]>
    [064bit prompt]> # ---------- GCC ----------
    [064bit prompt]> gcc -fPIC -o main_cyg_pc064_gcc main00.c -lm
    [064bit prompt]>
    [064bit prompt]> ./main_cyg_pc064_gcc
    FE_DIVBYZERO: 0x00000004
    FE_INEXACT: 0x00000020
    FE_INVALID: 0x00000001
    FE_OVERFLOW: 0x00000008
    FE_UNDERFLOW: 0x00000010
    FE_ALL_EXCEPT: 0x0000003D
    
    1 / 0: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000004
    
    log2(-1): -nan
    errno: 33
    fetestexcept(FE_ALL_EXCEPT): 0x00000001
    
    FLT_MAX * 2: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000028
    
    Done.
    
    [064bit prompt]>
    [064bit prompt]> # ---------- MinGW64 GCC ----------
    [064bit prompt]> x86_64-w64-mingw32-gcc -fPIC -o main_cyg_pc064_mgw64gcc main00.c -lm
    [064bit prompt]> ./main_cyg_pc064_mgw64gcc
    FE_DIVBYZERO: 0x00000004
    FE_INEXACT: 0x00000020
    FE_INVALID: 0x00000001
    FE_OVERFLOW: 0x00000008
    FE_UNDERFLOW: 0x00000010
    FE_ALL_EXCEPT: 0x0000003F
    
    1 / 0: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000004
    
    log2(-1): nan
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000001
    
    FLT_MAX * 2: inf
    errno: 0
    fetestexcept(FE_ALL_EXCEPT): 0x00000028
    
    Done.
    

Based on the above a pattern emerge (for MinGW): It appears that math functions (that I've tried):

  • Don't set errno

  • Set the exception flags

So you could try a (lame) workaround (RO: gainarie): add the definitions manually. Create the file

math.h (macro definitions kind of constant across various file versions):

#pragma once

#include <math.h>

#if !defined(MATH_ERRNO)
#  define MATH_ERRNO 1
#endif
#if !defined(MATH_ERREXCEPT)
#  define MATH_ERREXCEPT 2
#endif
#if !defined(math_errhandling)
//#  define math_errhandling  (MATH_ERRNO | MATH_ERREXCEPT)
// @TODO - cfati: changed value due to (above) results
#  define math_errhandling MATH_ERREXCEPT
#endif

and include it in your sources instead of the standard one.
But this might trigger Undefined Behavior, so beware of all the implications, although I think that MinGW was built without those flags, they have no effect in its built code, only (new) client code (like your program) should be influenced by them.
Also, some MinGW builds might behave differently, so this file (especially math_errhandling value) should be considered every time a new build is used.

发布评论

评论列表(0)

  1. 暂无评论