2

I was adding some GCC warning, and wanted to explicitly exclude some expressions and found a way by using #pragma diagnostic. However, I realized that depending where I put the pragma, the binaries can change.

For instance, consider the following snippet:

#include <stdio.h>

int f(int x, int y, int z);

int main()
{
    int x, y, z;
    scanf("%d%d%d", &x, &y, &z);
    f(x, y, z);
    return 0;
}

and the following two implementations of f(...):

  1. https://godbolt.org/z/hxWcf6h9s

    • Implementation of f:

      int f(int x, int y, int z)
      {
          #pragma GCC diagnostic push
          #pragma GCC diagnostic ignored "-Wparentheses"
          if (x || y && z)
          #pragma GCC diagnostic pop
          {
              return 1;
          }
          return 0;
      }
      
    • Generated code:

      f:
              push    rbp
              mov     rbp, rsp
              mov     DWORD PTR [rbp-4], edi
              mov     DWORD PTR [rbp-8], esi
              mov     DWORD PTR [rbp-12], edx
              mov     eax, 1
              pop     rbp
              ret
      
  2. https://godbolt.org/z/qdnhhKMjP

    • Implementation of f:

      int f(int x, int y, int z)
      {
          #pragma GCC diagnostic push
          #pragma GCC diagnostic ignored "-Wparentheses"
          if (x || y && z)
          {
          #pragma GCC diagnostic pop
              return 1;
          }
          return 0;
      }
      
    • Generated code:

      f:
              push    rbp
              mov     rbp, rsp
              mov     DWORD PTR [rbp-4], edi
              mov     DWORD PTR [rbp-8], esi
              mov     DWORD PTR [rbp-12], edx
              cmp     DWORD PTR [rbp-4], 0
              jne     .L2
              cmp     DWORD PTR [rbp-8], 0
              je      .L3
              cmp     DWORD PTR [rbp-12], 0
              je      .L3
      .L2:
              mov     eax, 1
              jmp     .L4
      .L3:
              mov     eax, 0
      .L4:
              pop     rbp
              ret
      

Compiled with gcc -std=gnu99 -Wparentheses -Werror -O0, result in different binaries. Why is that?

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
Berthin
  • 189
  • 2
  • 12
  • Please copy-paste errors or warning messages into the question itself, it's important to make it self-contained. And when you say "different", different *how*? Perhaps also include the generated assembly in the question as well? – Some programmer dude Apr 29 '21 at 10:12
  • There is no errors or warnings, the code compiles, but generates different binaries. – Berthin Apr 29 '21 at 10:13
  • In https://stackoverflow.com/a/47518775/4868875 it is mentioned that pragma works in a line-based approach rather than declaration-based. But not sure yet why the difference in this case. – Berthin Apr 29 '21 at 10:15
  • 1
    -O0 is not designed to produce efficient binaries, or optimal binaries, or binaries that do not depend on trivial changes in the code or compiler options, or anything like that. It doesn't make any sense to look at the resulting binaries and expect anything whatsoever except correctness and perhaps some debuggability. – n. m. could be an AI Apr 29 '21 at 12:54
  • 1
    @n.'pronouns'm. Thanks, but I don't see your point, are you saying that comparing the binaries with -O0 makes no sense? My goal is to understand the difference between the code with the pragma including the open curly bracket and the one that is not. – Berthin Apr 29 '21 at 13:13
  • 1
    Yes that's exactly what I'm a saying and my point is in saying that, nothing more. You can try to understand the difference but I don't think there's anything of value to be learned from it. With no optimisations the compiler produces code that is convenient to produce and it is unreasonable to expect that the same thing would be convenient regardless of diagnostic options. – n. m. could be an AI Apr 29 '21 at 13:31
  • 1
    @n.'pronouns'm.: The fact `-O0` is not designed a particular way does not mean it does not make any sense to examine the resulting binaries. Nothing in the natural world was designed, yet we learn a great deal by examining it—all of physics, biology, and more—and get a great deal of value from it. On the face of it, ignoring warnings has nothing to do with code generation, so the fact there is a difference suggests there is some connection. That connection where none is apparent on the face of it is of interest. Curiosity is valuable and should be encouraged, not discouraged. – Eric Postpischil Apr 29 '21 at 13:42
  • 2
    @n.'pronouns'm.: Potential things to learn might be some illumination about how the compiler is constructed. Or perhaps some semantics in the `#pragma` directives we were unaware of. Or some bug or shortcoming in the compiler. OP has found something odd, and investigating odd things may lead to interesting discoveries. You do not know until you look, and discouraging curiosity is bad policy. – Eric Postpischil Apr 29 '21 at 13:43
  • 1
    @n.'pronouns'm. with `-O3` the result still seems to be different. – sergej Apr 29 '21 at 13:50
  • @sergej one of them doesn't look correct. Could be a compiler bug. – n. m. could be an AI Apr 29 '21 at 14:31
  • @EricPostpischil You can examine the resulting binaries for correctness and see if there is a compiler bug (which seems to be the case here) but I'm not sure why anyone would do anything else. Different warning levels may well be achieved by using different parsers, one built for efficiency and one built for better diagnostics. If you want to know whether this is indeed the case, just read the compiler code. – n. m. could be an AI Apr 29 '21 at 14:38
  • @n.'pronouns'm.: Re “I'm not sure why anyone would do anything else”: That expresses a lack of knowledge. Guess how that is rectified. Re “just read the compiler code”: That is a change in argument. Previously, you asserted it does not make sense to “expect anything whatsoever except correctness and perhaps some debuggability.” Now you are saying what there is to be learned can be learned by looking at the compiler code. So you are tacitly admitting there may be things to be learned, and you are merely arguing you have a better method. That is questionable. It is called code for a reason. – Eric Postpischil Apr 29 '21 at 17:09
  • @n.'pronouns'm.: In any event, I maintain that discouraging inquiry is bad, even unethical. If somebody has a question, let them pursue it and do not discourage them. – Eric Postpischil Apr 29 '21 at 17:10
  • @EricPostpischilyes No idea why you are saying that. I'm saying that looking at the object code is not a good way to make meaningful conclusions about the language or compiler construction. Not that one should not try to learn. – n. m. could be an AI Apr 30 '21 at 12:38

0 Answers0