steve@vsi1.UUCP (Steve Maurer) (01/13/88)
[l] [line] [lineater] > > Why is everyone so interested in a power operator compared to, say, > > square root or logarithm? > > Basically, it's because exponentiation involving one or two integers > can usually be done much faster than through use of the floating-point > pow() function, and in the common case **2 can be highly optimized. While we are on the subject of useful additions to C, how about this one: pre-compiler switching operators '??' and '::', which ask for evaluation at compile time, instead of run time. For example, if a novice C user wished to create an optimized form of pow(), without knowing the true implementation of it he might write: #define POW(X,Y) (Y) == 0.5 ? sqrt(X) : ( (Y) == 0 ? 1 : ( (Y) == 1 ? X :\ ( (Y) == 2 ? X * X : pow(X,Y) ) ) ) intending to 'optimize' the resulting code. Unfortunately, because of the way these operators work, the resulting code is horrendous. Consider however, the efficiency gained if the operators are evaluated at compile time. Presuming of course that (Y) above is a CONSTANT, various in line efficiencies could be squeezed out of a machine without resorting to numerous additions to the language. The actual definitions of '??' and '::' would be: * if in the precompiler, the expression evaluates to TRUE, then the statement immediately following ?? is produced, else the statment following the :: is produced. If no :: is present, and the expression value cannot be determined in the precompiler, then no code is produced. So in the above example, with all "?" replaced by "??" and ":" replaced by "::", the expression POW(i, 20/10) would be replaced by i * i, with no comparisons in the resulting assembly. { Of course you would still have to deal with the macro incremental assignment problem - e.g. POW(i++,3) - but such is life } Ok, boys. Shoot it down....... Steve Maurer
gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/14/88)
In article <253@vsi1.UUCP> steve@vsi1.UUCP (Steve Maurer) writes: > Ok, boys. Shoot it down....... Practically any real C compiler will optimize away "dead" expressions resulting from folding constants.
karl@haddock.ISC.COM (Karl Heuer) (01/14/88)
In article <253@vsi1.UUCP> steve@vsi1.UUCP (Steve Maurer) writes: >While we are on the subject of useful additions to C, how about this >one: pre-compiler switching operators '??' and '::', which ask for >evaluation at compile time, instead of run time. The proposed syntax is bad: "??" conflicts with trigraph notation (if they're still in the standard), and "::" conflicts with C++ usage. >[If one attempts to define a macro POW(X,Y) as >Y == 0.5 ? sqrt(X) : Y == 0 ? 1 : Y == 1 ? X : Y == 2 ? X * X : pow(X,Y) >,] the resulting code is horrendous. If Y is a constant, any decent compiler will do the right thing. You don't need a new operator for that. If I understand your proposal, the only real enhancement is that "??" treats all non-constants as false. I counterpropose a builtin "isconstant()", which tests whether its argument is a compile-time constant. Thus, "isconstant(Y) && Y == 2 ? X * X : pow(X,Y)". This is a much smaller change than your proposal, and it's much easier to squeeze in a new unary operator than a new ternary. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint ________ Note 1: I intentionally removed the redundant parens to make it easier to concentrate on the issues at hand. Note 2: Although "pow" is used in the example, a macro can't solve the pow() problem. However, C++ overloading and inlining, combined with isconstant(), would do the trick.
ned@ghostwheel.UUCP (Ned Nowotny) (01/23/88)
And now for something completely different... Given a compiler or lint that would understand the construct and issue warnings about type mismatches, I would like to see "struct *" used as a generic pointer to a structure. This is distinct from "void *" in that pointers to structures generally have the same alignment constraints in all implementations of which I am aware, but "char" and "short" frequently have different alignment constraints from other data types. The problem is that "void *" is a pun for all pointers, and pointers for all the other basic types (e.g. char, int, long, etc.) are puns for pointers to any objects of the same type. "struct *" (and maybe even "union *") could provide a similar generality for inhomogeneous aggregate data types. (As opposed to arrays which are homogeneous aggregate data types. Too bad they aren't first class citizens. Well, it's too late now. Or is it? ANSI C maybe? Nahh! ;-) ) -- Ned Nowotny (ned@ghostwheel.aca.mcc.com.UUCP)
gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/25/88)
In article <127@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes: >... I would like to see "struct *" used as a generic pointer to a structure. I didn't understand your "explanation", but I don't see what good this would be. It would seem to provide an unwanted escape from strict typing. Different structure types really ought not to have their pointers mixed up by the programmer.
karl@haddock.ISC.COM (Karl Heuer) (01/25/88)
In article <127@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes: >... I would like to see "struct *" used as a generic pointer to a structure. >This is distinct from "void *" in that pointers to structures generally have >the same alignment constraints in all implementations of which I am aware, Most implementations I've seen will give a struct the alignment of its strictest member. Thus, struct{char} and struct{int} may have different alignment constraints. However, I believe the dpANS requires that all struct pointers must be interchangable anyway, so this does not invalidate your suggestion. How would you use such a feature, if you had it? Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
gwyn@brl-smoke.ARPA (Doug Gwyn ) (01/26/88)
In article <2376@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes: >Thus, struct{char} and struct{int} may have different alignment constraints. I used to think that, too, but a few weeks ago after discussion with Dennis Ritchie I realized that all struct pointers have to "smell" the same, which implies that they might as well have the same alignment. The argument had to do with use of an incomplete struct type declaration in order to accomplish mutual reference in two struct declarations. The utility of maintaining a distinction between different struct types is simply for compile-time type checking, which is VERY helpful.
ned@ghostwheel.UUCP (Ned Nowotny) (02/05/88)
In article <7169@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >In article <127@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes: >>... I would like to see "struct *" used as a generic pointer to a structure. > >I didn't understand your "explanation", but I don't see what good this >would be. It would seem to provide an unwanted escape from strict typing. Well, its not "unwanted" and "strict typing" doesn't seem to apply to C. ;-) >Different structure types really ought not to have their pointers mixed >up by the programmer. I don't want to mix pointers to different structure types, but I do want to write generic code which manipulates complex objects (e.g. linked list managers). Currently, this requires declaring pointers as "char *" or "long *" (worse because its not even a convention, but possibly more correct when considering data alignment for a given implementation) in K&R C compilers, or "void *" in ANSI psuedo-compatible C compilers. I do not find either of these options particularly satisfying. "void *" is too indiscriminating with regard to structure alignment and "char *" or "long *" discriminate too much (besides, I want a pointer to a stucture of some kind, not a char or a long). "struct *" would suppress unwarrented complaints about possible integer/structure or character/structure alignment differences from lint or my compiler. Any remaining possible alignment problems would then be more likely to be treated as real problems and not line noise. The nice thing about this proposal is that it breaks absolutely no existing code, does not add any new keywords, and provides some additional type information to C's typing system. As a rational, consider that given: int a, b; int *a_ptr; declares a pointer which may freely point to either "a" or "b" even though the name implies that it should only point to "a". Despite the name, "a_ptr" is a generic integer pointer although "a" and "b" may be conceptually different objects. In fact, given: typedef int a_int; typedef int b_int; a_int a; b_int b; int *ptr; a_int *a_ptr; ptr = &a; a_ptr = &b; neither lint nor my compiler complain of type mismatches although they should if C supported strict typing. (This compiler is a BSD C compiler running on a VAX 11/750, but it is no different than any of a number of C compilers which I have used.) Of course, it is frequently desirable to have a generic pointer to an integer (a good thing because its all you get). In the same sense, it can be desirable to have a generic pointer to complex objects (i.e. structures). A "type" cast will be necessary to get at a structure's members through such a pointer, but this is generally not necessary where a "struct *" pointer would be used. After all, the intent is to have a handle on a some complex object, not to manipulate the object. -- Ned Nowotny (ned@ghostwheel.aca.mcc.com.UUCP)
karl@haddock.ISC.COM (Karl Heuer) (02/10/88)
In article <131@ghostwheel.UUCP> ned@ghostwheel.aca.mcc.com.UUCP (Ned Nowotny) writes: >[Re "struct *" for a generic pointer to a structure] >I don't want to mix pointers to different structure types, but I do want >to write generic code which manipulates complex objects (e.g. linked list >managers). How about writing "struct generic *", where "struct generic" is never defined? This is already syntactically and semantically legal. >As a rational, consider that given "int a, b;", "int *a_ptr;" declares a >pointer which may freely point to either "a" or "b" Yes; so "int *" is a pointer to any int. But it can't point to a short int or a long int. The analogy is pretty weak, I'd say. >In fact, given: "typedef int a_int; typedef int b_int;" [both cc and lint >allow mixing of the two types]. That's because typedef creates a new name for an existing type, rather than a new type. You want dimensional analysis? I'm working on it. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/11/88)
In article <2528@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes: >How about writing "struct generic *", where "struct generic" is never defined? >This is already syntactically and semantically legal. Is that really true? I think technically you're supposed to have to have pre-declared the incomplete type: struct generic; and that if the type is not later completed it's supposed to be an error.