karl@haddock.ISC.COM (Karl Heuer) (01/15/88)
In article <531@cresswell.quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: >Is there any reason why C compilers should not be allowed to assume the >truth of assertions even in the presence of NDEBUG? I like the idea. There are a few problems; let's formalize. Subproposal A: Whether or not NDEBUG is set, assert() shall always evaluate its argument for side effects. Rationale: Although current implementations do not conform to it, the proposal is easy to implement ("#define assert(e) ((void)(e))") and makes assert() more useful ("assert(getchar() == '\n')"). This should not break any existing code, because anything which depends on the argument *not* being evaluated will behave differently depending on whether NDEBUG is set or not. Subproposal B: The macro shall expand into a void expression. Rationale: This would guarantee that it is legal in an expression context, e.g. "y = 1.0 / (assert(x!=0.0), x)". This isn't critical, but it helps prevent surprising behavior in some contexts. Subproposal C: If the argument of assert() is true (compares unequal to zero), then the macro returns no value. Else, if the NDEBUG macro is not defined, then a message is printed and the abort() function is invoked. (At this point we still agree with the dpANS; the next statement is the proposal.) Else, the behavior is undefined. Rationale: One normally defines NDEBUG for optimization. The code has been tested without NDEBUG and verified to be correct; the programmer no longer wants the overhead of an explicit run-time check. If the behavior in the third case is undefined, the compiler may be able to generate better code by assuming that the assertion is true. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint ________ Note: according to Walter Bright's article <1459@dataio.Data-IO.COM>, it seems that current optimizer technology won't handle anything much more complex than "assert(x == 3)" or "assert(x == y)".
dsill@NSWC-OAS.arpa (Dave Sill) (01/16/88)
In article <2276@haddock.ISC.COM> Karl Heuer <karl@haddock.ISC.COM> writes: >Subproposal A: Whether or not NDEBUG is set, assert() shall always evaluate >its argument for side effects. Doesn't this defeat the purpose of NDEBUG? Granted, the diagnostic-generating code would be left out, but the expression evaluation code would remain. >Subproposal B: The macro shall expand into a void expression. > >Rationale: This would guarantee that it is legal in an expression context, >e.g. "y = 1.0 / (assert(x!=0.0), x)". This isn't critical, but it helps >prevent surprising behavior in some contexts. I may be missing something here, but I don't see where it makes much difference what type `assert' expands to. The example would work if it expanded to an `int'. >Subproposal C: If the argument of assert() is true (compares unequal to zero), >then the macro returns no value. Else, if the NDEBUG macro is not defined, >then a message is printed and the abort() function is invoked. (At this point >we still agree with the dpANS; the next statement is the proposal.) >Else, [assertion is false and NDEBUG is defined,] behavior is undefined. I like this. After all, the assertion is false... ======== The opinions expressed above are mine. "Damn it, wine is liquid food!" -- Robert Mondavi
karl@haddock.ISC.COM (Karl Heuer) (01/18/88)
In article <11295@brl-adm.ARPA> dsill@NSWC-OAS.arpa (Dave Sill) writes: >In article <2276@haddock.ISC.COM> Karl Heuer <karl@haddock.ISC.COM> writes: >>Subproposal A: ... assert() shall always evaluate its argument ... > >Doesn't this defeat the purpose of NDEBUG? ... The expression evaluation >code would [still be generated]. If the expression has side effects, I think it's clear that the user does want them to be evaluated. If the expression has no side effects, the compiler is free to generate zero instructions. (I realize that there are some pretty bad nonoptimizing compilers out there. I wish there were fewer.) >>Subproposal B: The macro shall expand into a void expression. [To guarantee >>that it is legal in an expression context.] > >I may be missing something here, but I don't see where it makes much >difference what type `assert' expands to. The intended emphasis was on "expression", not "void". Some implementations currently expand assert() into nothing at all (when NDEBUG is set) and/or a non-expression statement (when NDEBUG is unset). As for the type, since the synopsis says "void assert(int)", why not require the implementation to enforce it? All it takes is a (void) cast, and it catches more errors. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
franka@mmintl.UUCP (Frank Adams) (01/19/88)
In article <2300@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes: >If the expression has side effects, I think it's clear that the user does want >them to be evaluated. If the expression has no side effects, the compiler is >free to generate zero instructions. This is fine as long as the assert expression calls no functions. But unless you in an environment which permits global optimization, which most of us aren't, the compiler will have to make any function calls which are used in the expression. This would include, for example, assert(pow(x, 2) < y) -- to touch on another recent topic of discussion. -- Frank Adams ihnp4!philabs!pwa-b!mmintl!franka Ashton-Tate 52 Oakland Ave North E. Hartford, CT 06108
karl@haddock.ISC.COM (Karl Heuer) (01/21/88)
In article <2662@mmintl.UUCP> franka@mmintl.UUCP (Frank Adams) writes: >In article <2300@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes: >>If the expression has side effects, I think it's clear that the user does >>want them to be evaluated. > >This is fine as long as the assert expression calls no functions. ... >[But what about] assert(pow(x, 2) < y) Good point. I was thinking in terms of functions with desirable side effects, in particular things like assert(getchar() == '\n') . Okay, world. Do you use <assert.h>? Do you have any/much existing code that uses benign function calls within assert? Is it worth "breaking"% that code in exchange for the added benefit of being able to use arbitrary expressions with impunity? Send mail; I'll post a summary. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint %The proposed change wouldn't invalidate such a program, but it would probably cause extra code to be generated/executed.
ado@elsie.UUCP (Arthur David Olson) (01/22/88)
Up to a year ago, I believed that the ANSI standard should set things up so that the "argument" of assert was always evaluated--even when NDEBUG was defined. Now that I worry more about "following existing practice," I believe that assert's argument should *not* be evaluated when NDEBUG is defined, since most existing implementations don't evaluate it. Which needn't stop the committee from tossing the lines #if defined NDEBUG #define demand(x) ((void) (x)) #else /* !defined NDEBUG */ #define demand(x) assert(x) #endif /* !defined NDEBUG */ into "assert.h" (with suitable documentation). (Failing that, you can toss the lines into your own code.) -- ado@vax2.nlm.nih.gov ADO, VAX, and NIH are Ampex and DEC trademarks