Search code examples
clanguage-lawyerundefined-behaviorc89

Why is using an identifier not in scope UB and not an error


I quote from the ANSI_ISO+9899-1990, in the list of all Undefined Behaviors -

  • An identifier is used that is not visible in the current scope

Why is use of undefined variable UB and not an error? I want to know the reasoning behind this? Is it valid to make everything that is not "correct" as UB?

I know most of the compilers treat it as errors. But why does the standard say this?

Or there is no notion of "error" in the standard? The grammar of c is .* but some part of it has UB?


Solution

  • No, there is very much a concept of errors in the standard, it's just that not everything counts as an error. I'll say two things up front which may help you out here:

    1. C89/90 was to codify existing practice, not to create a new language. That means it was sometimes necessary to compromise on things even when they didn't make sense.

    2. C99+ did not have that restriction so certain things were able to be cleaned up. In fact, since that text you quote appears to disappear in C99, this may well be one of the things cleaned up.

    Back to the reasoning, the ANSI C89 rationale document has this to say:

    One source of dispute was whether identifiers with external linkage should have file scope even when introduced within a block. The Base Document is vague on this point, and has been interpreted differently by different implementations. For example, the following fragment would be valid in the file scope scheme, while invalid in the block scope scheme:

    typedef struct data d_struct ;
    first(){
        extern d_struct func();
        /* ...  */
    }
    second(){
        d_struct n = func();
    }
    

    While it was generally agreed that it is poor practice to take advantage of an external declaration once it had gone out of scope, some argued that a translator had to remember the declaration for checking anyway, so why not acknowledge this? The compromise adopted was to decree essentially that block scope rules apply, but that a conforming implementation need not diagnose a failure to redeclare an external identifier that had gone out of scope (undefined behavior).

    It's almost certainly that phrase "has been interpreted differently by different implementations" which caused them to mark it as UB rather than an error. And note that it's not the scope that is in question here, just whether an implementation needs to report the fact you're trying to use it.