Search code examples
clinuxmacosgccundefined-behavior

Same C code, different output on Mac & Linux


I was messing with pointers and const, while running below code:

int main()
{
    const int test = 10;
    int *ptr = &test;
    printf("%d\n", test);
    *ptr = 1;
    printf("%d\n", test);
}

on Mac, results were:

10
10

and on the linux machine:

10
1

Why change of value didn't worked at Mac? Both machines compiled code with gcc.


Solution

  • You can run your tests on Godbolt's compiler explorer: https://godbolt.org/z/5xfEqj9x1

    As can be seen on the output panes, the behavior is consistent with your observations, here are some explanations:

    • the code has undefined behavior: you define test as a const int local variable but you explicitly bypass this by storing its address to an int * pointer and set the value via *ptr = 1. Both compilers issue a warning about this dubious assignment, which you purposely ignored. The code *ptr = 1 has undefined behavior because you are modifying a const variable. If test had been defined at the global scope (or with a static qualifier) this assignment might have triggered a segmentation fault. In this case, the indirect modification of the variable, if performed at all has no effect because the compiler may assume that the test variable does not change.

    • gcc on macOS is by default an alias for clang, which generates different code from gcc on linux. Even without optimisations, clang assumes that the const variable has not been modified between the 2 printf statements and passes 10 as the argument value (via the esi register) in both calls. gcc does this with -O2 or higher optimisation level, but reads the variable value at -O0, producing 1 for the second printf call on linux.

    Executing code with undefined behavior implies anything can happen and different output is a common illustration, which is frustrating because the environment does not point to the problem as explicitly as a segmentation fault would. anything can happen is not to be taken literally, it means unpredictable side effects or lack thereof can happen, including nothing visible, a different value being read, a segmentation fault occurring... Expect the unexpected.

    To try and minimize such problems, always add all useful warnings at compile time and fix their causes (eg: -Wall -Wextra -Werror).