Search code examples
c++ffmpegclangemscripten

FFmpeg compilation warnings ATOMIC_VAR_INIT


While compiling ffmpeg (commit 1368b5a) with emscripten 3.1.17, there are two warnings, I would like the internet to help me better understand (I am not someone with deep c++ experience):

fftools/ffmpeg.c:339:41: warning: macro 'ATOMIC_VAR_INIT' has been marked as deprecated [-Wdeprecated-pragma]
static atomic_int transcode_init_done = ATOMIC_VAR_INIT(0);
                                        ^
/home/XYZ/ffmpeg-wasm/modules/emsdk/upstream/lib/clang/15.0.0/include/stdatomic.h:50:41: note: macro marked 'deprecated' here
#pragma clang deprecated(ATOMIC_VAR_INIT)
                                        ^

I understand ATOMIC_VAR_INIT in this place is deprecated, but by which tool (emscripten, clang)? And which party to be involved in the fix.

The other one is also interesting:

fftools/ffmpeg_filter.c:898:35: warning: floating-point comparison is always true; constant cannot be represented exactly in type 'float' [-Wliteral-range]
        if (audio_drift_threshold != 0.1)
            ~~~~~~~~~~~~~~~~~~~~~ ^  ~~~

The message and consequences are very clear. Whats not clear to me, is, if this is particular compiler issue, or code issue and which party to take care?


Solution

  • For ATOMIC_VAR_INIT I found this note:

    This macro was a part of early draft design for C11 atomic types. It is not needed in C11, and is deprecated in C17 and removed in C23.

    So, the deprecation was by the C standard (and the C++ standard, though there it was deprecated in C++20)

    As for the floating point issue, the compiler states outright that:

    constant cannot be represented exactly in type 'float'

    Which is entirely true. In binary every bit of a number represents a power of two. In integers it is fairly easy, the bits represent 1,2,4,8,16,32,64,... matching 2 to the power of 0,1,2,3,4,5,6,...

    For example the integer: 0b100101 is (low bit it to the right): 1+4+32=37.

    Floating points are roughly the same, but with a few more complications (which I will skip here). Basically the bits now represent negative powers of two: 0.5, 0.25, 0.125, 0.0625, ... But unfortunately this does not allow us to represent all possible decimal numbers (this is an impossible task, there are infinitely many decimal numbers between 0 and 1, and we only have a finite number of combinations with a finite number of bytes).

    It turns out that 0.1 is one of the numbers that it is impossible to encode in binary floating point. Which makes sense as 0.1 is 1/2 * 1/5, and 1/5 cannot be represented as a power of 2.

    If you do the math, you find that:

    2^-4 + 2^-5 + 2^-8 + 2^-9 + 2^-12 + 2^-13 = 0.0999755859375

    If you continue this sequence forever (skip two powers, add two powers, repeat), then you will get infinitely close to 0.1. But that is the best we can do.

    If you want to do some more reading, then here is some links:

    Now, the part I am a bit unsure of is:

    warning: floating-point comparison is always true

    Technically 0.1 should translate to some bit-pattern, and if you then throw a variable with that exact same bit pattern at the != check, then the result should be false. But perhaps the compiler made an executive decision and just said: "Always true", because getting the exact bit pattern is super unlikely and fragile.

    But whatever the case, and more importantly: float != 0.1 is a really bad test. The links I put above elaborate on it much better than I can, but basically you don't ever want to test a floating point for strict equality - you always want to add an epsilon of some value (it depends on the numbers you compare).

    For example: abs(float - 0.1) < epsilon.