"Strong typing vs. strong testing"

Keith Thompson kst-u at mib.org
Thu Sep 30 16:34:44 EDT 2010


Seebs <usenet-nospam at seebs.net> writes:
> On 2010-09-30, Keith Thompson <kst-u at mib.org> wrote:
>> Seebs <usenet-nospam at seebs.net> writes:
>>> On 2010-09-30, Paul Rubin <no.email at nospam.invalid> wrote:
>>>>     int maximum(int a, int b);
>
>>>>     int foo() {
>>>>       int (*barf)() = maximum;
>>>>       return barf(3);
>>>>     }
>
>> That first line declare barf as an object of type "pointer to
>> function returning int", or more precisely, "pointer to function with
>> an unspecified but fixed number and type of parameters returning int"
>> (i.e., an old-style non-prototype declaration, still legal but
>> deprecated in both C90 and C99).  It then initializes it to point
>> to the "maximum" function.  I *think* the types are sufficiently
>> "compatible" (not necessarily using that word the same way the
>> standard does) for the initialization to be valid and well defined.
>> I might check the standard later.
>
> Hmm.  You have a point.  It's clearly a conversion from one type
> to another.

If I'm reading 6.7.5.3p15 correctly, the types
    int (*)()
and
    int (*)(int, int)
are compatible, so the declaration and initialization of barf is
perfectly legal, and a call
    bar(3, 4)
would also be legal and would return 4.

I actually didn't notice on my initial reading that the call is passing
the wrong number of arguments.  Since the type of barf doesn't specify
the number or types of the arguments, no diagnostic is required, but
the behavior is undefined.

>> IMHO it's better to use prototypes consistently than to figure out the
>> rules for interactions between prototyped vs. non-prototyped function
>> declarations.
>
> Yes.  It's clearly undefined behavior to call a function through a
> pointer to a different type, or to call a function with the wrong number
> of arguments.  I am pretty sure at least one compiler catches this.

The former is not a problem here; the type of barf is compatible with
the type of a pointer to maximum.  The latter is the problem, and a
sufficiently clever compiler can warn about it.

Note that you could do something silly like this:

    int one_param(int a);
    int two_params(int a, int b);
    int (*barf)();
    if (some_condition) {
        barf = one_param;
    }
    else {
        barf = two_params;
    }
    if (some_other_condition) {
        barf(1);
    }
    else {
        barf(2, 3);
    }

No constraint violations, and no undefined behavior as long as
some_condition and some_other_condition have the same value.
The best a compiler can do (unless it knows about the conditions)
is warn you that something *might* go wrong.

For programmers, the solution is simple: *Don't do that!*.

-- 
Keith Thompson (The_Other_Keith) kst-u at mib.org  <http://www.ghoti.net/~kst>
Nokia
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"



More information about the Python-list mailing list