Why is it impossible to build a compiler that can determine if a C++ function will change the value of a particular variable?

后端 未结 13 737
感动是毒
感动是毒 2021-01-30 02:01

I read this line in a book:

It is provably impossible to build a compiler that can actually determine whether or not a C++ function will change the val

相关标签:
13条回答
  • 2021-01-30 02:43

    Really surprised that there isn't an answer that using the halting problem directly! There's a very straightforward reduction from this problem to the halting problem.

    Imagine that the compiler could tell whether or not a function changed the value of a variable. Then it would certainly be able to tell whether the following function changes the value of y or not, assuming that the value of x can be tracked in all the calls throughout the rest of the program:

    foo(int x){
       if(x)
           y=1;
    }
    

    Now, for any program we like, let's rewrite it as:

    int y;
    main(){
        int x;
        ...
        run the program normally
        ...
        foo(x);
    }
    

    Notice that, if, and only if, our program changes the value of y, does it then terminate - foo() is the last thing it does before exiting. This means we've solved the halting problem!

    What the above reduction shows us is that the problem of determining whether a variable's value changes is at least as hard as the halting problem. The halting problem is known to be incomputable, so this one must be also.

    0 讨论(0)
  • 2021-01-30 02:43

    To expand on my comments, that book's text is unclear which obfuscates the issue.

    As I commented, that book is trying to say, "let's get an infinite number of monkeys to write every conceivable C++ function which could ever be written. There will be cases where if we pick a variable that (some particular function the monkeys wrote) uses, we can't work out whether the function will change that variable."

    Of course for some (even many) functions in any given application, this can be determined by the compiler, and very easily. But not for all (or necessarily most).

    This function can be easily so analysed:

    static int global;
    
    void foo()
    {
    }
    

    "foo" clearly does not modify "global". It doesn't modify anything at all, and a compiler can work this out very easily.

    This function cannot be so analysed:

    static int global;
    
    int foo()
    {
        if ((rand() % 100) > 50)
        {
            global = 1;
        }
        return 1;
    

    Since "foo"'s actions depends on a value which can change at runtime, it patently cannot be determined at compile time whether it will modify "global".

    This whole concept is far simpler to understand than computer scientists make it out to be. If the function can do something different based on things can change at runtime, then you can't work out what it'll do until it runs, and each time it runs it may do something different. Whether it's provably impossible or not, it's obviously impossible.

    0 讨论(0)
  • 2021-01-30 02:44

    It can be done and compilers are doing it all the time for some functions, this is for instance a trivial optimisation for simple inline accessors or many pure functions.

    What is impossible is to know it in the general case.

    Whenever there is a system call or a function call coming from another module, or a call to a potentially overriden method, anything could happen, included hostile takeover from some hacker's use of a stack overflow to change an unrelated variable.

    However you should use const, avoid globals, prefer references to pointers, avoid reusing variables for unrelated tasks, etc. that will makes the compiler's life easier when performing aggressive optimisations.

    0 讨论(0)
  • 2021-01-30 02:44

    Even if a variable is declared const, doesn't mean some badly written code can overwrite it.

    //   g++ -o foo foo.cc
    
    #include <iostream>
    void const_func(const int&a, int* b)
    {
       b[0] = 2;
       b[1] = 2;
    }
    
    int main() {
       int a = 1;
       int b = 3;
    
       std::cout << a << std::endl;
       const_func(a,&b);
       std::cout << a << std::endl;
    }
    

    output:

    1
    2
    
    0 讨论(0)
  • 2021-01-30 02:45

    Don't confuse "will or will not modify a variable given these inputs" for "has an execution path which modifies a variable."

    The former is called opaque predicate determination, and is trivially impossible to decide - aside from reduction from the halting problem, you could just point out the inputs might come from an unknown source (eg. the user). This is true of all languages, not just C++.

    The latter statement, however, can be determined by looking at the parse tree, which is something that all optimizing compilers do. The reason they do is that pure functions (and referentially transparent functions, for some definition of referentially transparent) have all sorts of nice optimizations that can be applied, like being easily inlinable or having their values determined at compile-time; but to know if a function is pure, we need to know if it can ever modify a variable.

    So, what appears to be a surprising statement about C++ is actually a trivial statement about all languages.

    0 讨论(0)
  • 2021-01-30 02:47

    Why is it impossible to build such a compiler?

    For the same reason that you can't write a program that will determine whether any given program will terminate. This is known as the halting problem, and it's one of those things that's not computable.

    To be clear, you can write a compiler that can determine that a function does change the variable in some cases, but you can't write one that reliably tells you that the function will or won't change the variable (or halt) for every possible function.

    Here's an easy example:

    void foo() {
        if (bar() == 0) this->a = 1;
    }
    

    How can a compiler determine, just from looking at that code, whether foo will ever change a? Whether it does or doesn't depends on conditions external to the function, namely the implementation of bar. There's more than that to the proof that the halting problem isn't computable, but it's already nicely explained at the linked Wikipedia article (and in every computation theory textbook), so I'll not attempt to explain it correctly here.

    0 讨论(0)
提交回复
热议问题