gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/26/88)
In article <264@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >In article <1988Nov22.170953.24489@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: > Definitions of parameterized macros ("function-like" macros in > X3J11speak) have always been required to have the "(" immediately > following the identifier. The May draft standard requires that in > the invocation, the "(" must be "the next preprocessor token", > which basically means that white space there is okay. >Now I have always had a low opinion of the X3J11 work (e.g. not to >realize that unsigned and int are different types, as they obey >different rules for arithmetic, and char short and long are just >range/length modifiers, and not the other way round), but this last >idea really leaves me gasping... It would be nice if you checked what X3J11 had done before venturing an opinion. In the dpANS, unsigned and int are definitely different types, as they always have been in C. If you're referring to the adoption of "value preserving" rules for type conversion, that is clearly a logical improvement over "sign preserving" rules, leading to surprising behavior less often, and turned out upon investigation to not break a significant amount of code already written according to sign-preserving rules. Both variations were found in existing practice before X3J11 had to make a choice, and they chose the patently better set of rules. char never has been a "range/length" modifier in C, and X3J11 hasn't tried to change that. short and long have always produced different types, not different versions of the same type, and X3J11 hasn't tried to change that, either. >Obviously there must me a way to distinguish between macro bodies that >begin with a "(" and macro definitions with a parameter list, is there >one ? Yes, the ( introducing the parameters in the definition of a function- like macro must not be preceded by white space. Both the May draft and the current dpANS denote this special ( by the syntactic category "lparen", which it defines correctly. Henry was mistaken about this.
gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/26/88)
In article <8982@smoke.BRL.MIL> I wrote: >"sign preserving" To forestall yet another round of comments, please read this as the technically more accurate "unsigned preserving". Thanks.
chris@mimsy.UUCP (Chris Torek) (11/27/88)
>>In article <1988Nov22.170953.24489@utzoo.uucp> henry@utzoo.uucp >>(Henry Spencer) writes: >>>Definitions of parameterized macros ... have always been required to >>>have the "(" immediately following the identifier. The May draft >>>standard requires that in the invocation, the "(" must be "the next >>>preprocessor token", which basically means that white space there is okay. Translation: #define IDENT(a) (a) IDENT ( foo ) is perfectly legal and produces `foo'; #define ANAME (bar) ANAME(a,b) produces `(bar)(a, b)' (syntactically a function call). >In article <264@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: [much not worth quoting] In article <8982@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes: >It would be nice if you checked what X3J11 had done before venturing an >opinion. Indeed. However: >If you're referring to the adoption of "value preserving" rules for type >conversion, that is clearly a logical improvement over "sign preserving" >rules, leading to surprising behavior less often, and turned out upon >investigation to not break a significant amount of code already written >according to sign-preserving rules. Both variations were found in >existing practice before X3J11 had to make a choice, and they chose the >patently better set of rules. All of this is true save the `clearly ... improvement', `surprising ... less often', and `patently better' (which are all opinions). The problem with value-preserving rules is that predicting the type of of an expression requires knowing something that cannot be known portably: it requires knowing whether the expanded (rvalue) type of an lvalue actually contains more bits than the lvalue's type. That is, the type of the expansion of an `unsigned short' might be `unsigned int' or `int', and there is no way to tell which. (It is, however, true that casting to whichever type is desired will patch things up and eliminate any difference between the two methods.) >[parentheses in macro def/ref:] Henry was mistaken about this. While he did not use dpANS phrasing, he did get the details right. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/27/88)
In article <14724@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >>In article <264@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >[much not worth quoting] >(It is, however, true that casting to whichever type is desired will >patch things up and eliminate any difference between the two methods.) Which is another reason the difference between "value preserving" and "unsigned preserving" rules isn't very important: anyone who cares will be using explicit casts to be sure the proper conversions occur. >In article <8982@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes: >>[parentheses in macro def/ref:] Henry was mistaken about this. >While he did not use dpANS phrasing, he did get the details right. He may have. However, I think Grandi interpreted him as saying that white space was allowed before the ( in the DEFINITION of a function- like macro, and I was responding to that. #define foo (x) ((x)+1) foo(z) produces after substitution: (x) ((x)+1)(z) whereas #define foo(x) ((x)+1) foo (z) produces ((z)+1) X3J11 isn't proposing to change the way this has always worked.
pcg@aber-cs.UUCP (Piercarlo Grandi) (11/27/88)
I am happy I managed to sidetrack the sterile discussion on macros in cpp into something dearer to my heart (can you say "axe to grind" ? I can ;->...). I am relieved that the dpANS does not imply prescience and telepathy are required in cpp or the compilers to understand which macros are parameterless and which are not :-) :-)... On the other hand the substance of my point on unsigned/int remains; I apologize to Doug Gwin for having used the wrong terminology. What I really was unhappy with in dpANS (among many other things...) is that signed has been introduced as a new keyword, and I ought to have said unsigned/signed, not unsigned/int. As I understand it, this means that char,short,int,long are distinct types, whereas unsigned and signed are type modifiers. In a sense then, the view of dpANS is that unsigned [int] and [signed] int are the same type, only that one has a sign and the other hasn't. Clearly this mostly is a matter of emphasis, in that unsigned short and signed short are distinct types, as would be short unsigned and short int, but it is quite important to note that in dpANS there is an explicit affinity between unsigned and signed short, not between short and long unsigned, even if we concede that type modifiers create new types, instead of merely subtypes. I would not agree that char has never been a length specifier for int; before dpANS, C was defined by Ritchie's and Johnson's compilers (in a sense even K&R was just the manual for the compilers). In both compilers, and reading carefully K&R, one has the strong impression that, beyond a somewhat artificial distinction between integral and integer types, char was always meant to be a kind of short short int, and indeed one can apply to a char all the same operations one can apply to an integer; also the rules about lengtheneing of char and short in many contexts, and the common use of int where char could have been used, tend to reinforce the impression. I would also not agree that in this matter dpANS respected existing practice; the introduction of the signed modifier is certainly an innovation, and a confusing one as well (judging from all the fuss about it and char). In Johnson's compiler instead one can fully use char,short,long as type modifiers, and int and unsigned as based types, and I regard this (in my never humble opinion) as the most natural thing to do, and one that would not have required the introduction of signed. I understand that using a compiler as definition of a language is not kosher, but before dpANS this was the way (fortunately :->). Using this interpretation, there is little argument about adopting a "[un]signed preserving" or "value preserving" rule; the only rules are that conversion from a shorter to a long form of the same type results in no changes, and tyhe same applies when a longer value is shortened to a length that can represent it, and conversion across the two base types is defined only if the source unsigned is not too large or the source int is not too large or negative; anything else is machine dependent, except that truncations to a length of unsigned must respect the rules of modular arithmetic. This interpretation may not be what Ritchie, Johnson and K&R meant, but it is consistent with them (well, I admit that saying char int and char unsigned is somewhat funny, but you can get used to it ;-}), especially with the point that unsigned obeys a different type of laws of arithmetic (modular) than int (algebraic), thus distinguishing them more forcefully than differences of range, that after all are just accidents of implementation. Note also that there is no need of a signed keyword to disambiguate between variations of char in this interpretation; char by itself may be either, char int and char unsigned are well defined. As to the rest of dpANS, I will not rekindle spent discussions, except for a cheap leer at trigraphs :-) :-) (I understand that the committee were more or less forced to include them, so it is not wholly their fault...). As Ritchie said (more or less) in an interview to Computer Language: "dpANS C is the best standard that could have come out of a committee". -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
guy@auspex.UUCP (Guy Harris) (11/29/88)
>What I really was unhappy with in dpANS (among many other things...) is >that signed has been introduced as a new keyword, and I ought to have >said unsigned/signed, not unsigned/int. The reason why it was introduced has nothing to do with X3J11's opinion on whether "int" and "unsigned int" are similar types or not. It was introduced solely to provide a way for a programmer to specify that a "char"-sized variable is to be signed; presumably, it applies to "short", "int", and "long" purely for orthogonality. >I would not agree that char has never been a length specifier for int; The only way you can validly disagree with that statement is if you can produce a compiler wherein "char int" is a valid type specifier. I have yet to see any such compiler. >In Johnson's compiler instead one can fully use char,short,long as type >modifiers, and int and unsigned as based types, Funny, the SunOS C compiler is based on Johnson's PCC, and when I try to compile foo() { char int x; } it complains about an "illegal type modification". That compiler, at least, sure doesn't let you use "char" as a type modifier.... >and I regard this (in my never humble opinion) as the most natural >thing to do, and one that would not have required the introduction of >signed. I don't regard it as the most natural thing to do. I would have preferred it had C made a distinction between: 1) a type that was the unit of storage allocation; 2) a type that was a "character", and that might require a transfer function to convert between it and integral types (big deal, the main loop of a character-string-to-decimal routine might have included n = n*10 + (int(c) - int('0')); instead of n = n*10 + (c - '0'); even if the language didn't specify an automatic character-to-int conversion here, people could have lived with it); 3) a very small integral type. For various reasons, including the crudely practical one of the behavior of debuggers when confronted with "char", I tend to think of characters and integral types as different sorts of beasts.
jss@hector.UUCP (Jerry Schwarz) (11/29/88)
In article <277@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) makes some groundless attacks on the ANSI commitee apparently due to misunderstanding the (proposed) standard. I respond to one case in which either he or I have clearly misunderstood something. > >Using this interpretation, there is little argument about adopting a >"[un]signed preserving" or "value preserving" rule; the only rules are >that conversion from a shorter to a long form of the same type results >in no changes, and tyhe same applies when a longer value is shortened >to a length that can represent it, and conversion across the two base >types is defined only if the source unsigned is not too large or the >source int is not too large or negative; anything else is machine >dependent, except that truncations to a length of unsigned must respect >the rules of modular arithmetic. This is pretty much what the standard says about conversions, but it in no way resolves the difference between the "value preserving" and "unsigned preserving" rules. These address a different question. Namely the types of certain expressions. For example what is the type of i+us (where i is an int, and us is an unsigned short). Jerry Schwarz AT&T Bell Labs, Murray Hill
bill@twwells.uucp (T. William Wells) (11/30/88)
In article <277@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes:
: As I understand it, this means that char,short,int,long are distinct
: types, whereas unsigned and signed are type modifiers. In a sense then,
: the view of dpANS is that unsigned [int] and [signed] int are the same
: type, only that one has a sign and the other hasn't.
These are the C int-ish types
the types other ways of saying the same type
char
signed char
unsigned char
signed short int short, signed short, short int
unsigned short int unsigned short
signed int int, signed (or nothing, in some cases)
unsigned int unsigned
signed long int long, signed long, long int
unsigned long int unsigned long
(The order of the words is irrelevant.)
---
If you want to, you can think of this as types and modifiers, though
the standard does not speak of them that way. If so, here is how you
do it:
The types:
char
int
That's right. Only two.
The modifiers:
unsigned signed
short long
The first pair modifies char or int; the second int only. You can
specify only one of each pair.
---
Here are the characteristics of the types:
signedness values
char * *
signed char signed no smaller integer range exists
unsigned char unsigned no smaller unsigned range exists
short signed contains signed char values
unsigned short unsigned contains unsigned char values
int signed contains short values
unsigned unsigned contains unsigned short values
long signed contains int values
unsigned long unsigned contains unsigned int values
* Char may be either signed or unsigned. However, it is always treated
as a distinct type. The characters in the source character set are
positive values, but anything else may be positive or negative.
There is no relationship between char and signed or unsigned char,
other than that they occupy the same amount of storage.
Each unsigned type must be able to represent the positive values of
its corresponding signed type. Signed and unsigned types must occupy
the same amount of storage.
---
Bill
{uunet|novavax}!proxftl!twwells!bill
ggs@ulysses.homer.nj.att.com (Griff Smith) (12/01/88)
In article <9016@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: > "volatile" also serves a need. In fact, it directly addresses one of > the comments I saw earlier today in this newsgroup, about use of C for > accessing device registers. Again, it is transparent to virtually all > existing code, it addresses a real need, and it can be ignored by anyone > who does not specifically need it. What is your objection to it? I agree, and I don't object, but some brief encounters with an ANSI compiler make me worry about it a bit. The problem is that the existence of the volatile qualifier makes it possible to do optimizations that were previously forbidden (or at least difficult to slip past the customers). I blew several hours discovering that a flag set by a signal handler had been optimized out of existence because it wasn't declared volatile. If I were writing new software I would be aware of the problem and use the proper declaration, but what am I to do about fixing all the old stuff that now has subtle errors caused by optimizations that used to be illegal? The response I got from a C++ guru around here wasn't encouraging: he suggested declaring everything volatile and ignoring the issue. Maybe he's right, but that attitude could easily lead to a habit of forcing all declarations to include the volatile qualifier just to avoid a `silly' rule. This would negate any efficiency improvements the compiler designers were trying to achieve. Do any of you have some practical experience, plus suggestions for living in the brave new ANSI-C world? -- Griff Smith AT&T (Bell Laboratories), Murray Hill Phone: 1-201-582-7736 UUCP: {most AT&T sites}!ulysses!ggs Internet: ggs@ulysses.att.com
tps@chem.ucsd.edu (Tom Stockfisch) (12/02/88)
In article <10919@ulysses.homer.nj.att.com> ggs@ulysses.homer.nj.att.com (Griff Smith) writes: >In article <9016@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes: >> "volatile" also serves a need. In fact, it directly addresses one of... >.... I blew several hours discovering that a flag >set by a signal handler had been optimized out of existence because it >wasn't declared volatile. If I were writing new software I would be >aware of the problem and use the proper declaration, but what am I to >do about fixing all the old stuff that now has subtle errors caused by >optimizations that used to be illegal? Presumably there are only a few 1. Turn off optimizations (perhaps only some of them) when compiling signal handler modules. All relevant flags should be declared static in these files. 2. Access the flags in other modules only via function calls to routines in the signal handler modules. Now the compiler can't optimize away references to the flags. Of course, if your compiler does extensive global optimization (accross modules), you may still be in trouble. -- || Tom Stockfisch, UCSD Chemistry tps@chem.ucsd.edu
guy@auspex.UUCP (Guy Harris) (12/02/88)
>...but what am I to do about fixing all the old stuff that now has >subtle errors caused by optimizations that used to be illegal? Back off on the optimization level, if your compiler will let you? I think the SunOS optimizer is generally "safe" at level -O2 (that's the default level on Sun-4s, and only a very few modules crank it lower - mostly things like bitblt code, not e.g. all the kernel or all the device drivers): -O[level] Optimize the object code. Ignored when either -g, -go, or -a is used. On Sun-2 and Sun-3 systems, -O with the level omitted is equivalent to -O1; on Sun-4 systems, it is equivalent to -O2. on Sun386i systems, all levels are the same as 1. level is one of: 1 Do postpass assembly-level optimization only. 2 Do global optimization prior to code generation, including loop optimizations, common subexpression elimination, copy propagation, and automatic register allocation. -O2 does not optimize references to or defini- tions of external or indirect variables. 3 Same as -O2, but optimize uses and definitions of external variables. -O3 does not trace the effects of pointer assignments. Neither -O3 nor -O4 should be used when compiling either device drivers, or programs that modify exter- nal variables from within signal handlers. 4 Same as -O3, but trace the effects of pointer assignments. I suspect some compilers can be told to back off to a safer level as well.
henry@utzoo.uucp (Henry Spencer) (12/03/88)
In article <10919@ulysses.homer.nj.att.com> ggs@ulysses.homer.nj.att.com (Griff Smith) writes: >> "volatile" also serves a need... > >I agree, and I don't object, but some brief encounters with an ANSI >compiler make me worry about it a bit... Well, if I was to quibble, I would observe that there is no such thing as an ANSI C compiler yet, since there is no ANSI standard yet. In fact, any compiler that is actually in users' hands right now probably does not fully match even the current draft. End of quibble... >The problem is that the >existence of the volatile qualifier makes it possible to do >optimizations that were previously forbidden (or at least difficult to >slip past the customers). No, actually, it makes it possible for the users to defend themselves against optimizations that the compiler writers had in the works anyway. Even in the Good Old Days it wasn't uncommon to find machines where it was common knowledge that one should not compile tricky code (e.g. the kernel) with -O. >I blew several hours discovering that a flag >set by a signal handler had been optimized out of existence because it >wasn't declared volatile. If I were writing new software I would be >aware of the problem and use the proper declaration, but what am I to >do about fixing all the old stuff that now has subtle errors caused by >optimizations that used to be illegal? The old stuff always had subtle errors; the standard did not create them, it simply called them to your attention. The behavior of signal handlers has never been guaranteed in any way. Don't confuse "what I can get away with on a 4.2BSD VAX" with the definition of C. Those optimizations were never illegal, they just weren't common. The standard has actually improved the situation -- at least now you have behavior that you can count on. The only way to fix the old stuff is, well, to fix it. You can use a "#define volatile /* */" to make it compatible with old compilers. -- SunOSish, adj: requiring | Henry Spencer at U of Toronto Zoology 32-bit bug numbers. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
desnoyer@Apple.COM (Peter Desnoyers) (12/03/88)
>In article <10919@ulysses.homer.nj.att.com> ggs@ulysses.homer.nj.att.com (Griff Smith) writes: > >>.... I blew several hours discovering that a flag >>set by a signal handler had been optimized out of existence because it >>wasn't declared volatile. I've seen people blow days trying to get a pre-ANSI compiler to frob device registers properly. Not using '-O' doesn't turn off all optimizations in some (most?) compilers - just the ones in the optimizing pass. >If I were writing new software I would be aware of the problem and use >the proper declaration, but what am I to do about fixing all the old >stuff that now has subtle errors caused by optimizations that used to >be illegal? > Do what you did before - turn off optimization. Same solution, same results. pet peeve - It is a common thing to have to write a zero to a device register. The obvious code, (* reg_addr) = 0, often results in: xor reg_addr, reg_addr even with optimization off. This sucks - it reads the register twice, XORs the two (possibly different) values, and then writes the possibly non-zero value. If I wanted to read the register, I would have said so. I probably just cleared my data_ready flag or lost other input. The solution I have seen (pre-ANSI) was: extern int zero = 0; (* reg_addr) = zero; /* KLUDGE */ Unfortunately I don't think specifying bus semantics is within the purview of the ANSI committee (please correct me if I'm wrong - my knowledge of the details of the standard is limited) and volatile is not sufficient to force the desired activity. Peter Desnoyers
blarson@skat.usc.edu (Bob Larson) (12/03/88)
In article <21560@apple.Apple.COM> desnoyer@Apple.COM (Peter Desnoyers) writes: >pet peeve - It is a common thing to have to write a zero to a device >register. The obvious code, (* reg_addr) = 0, often results in: > > xor reg_addr, reg_addr What machine is this for? 3 memory references for a simple clear doesn't seem very good to me. Most 68000 compilers would use the clr instruction, which does have the undesired side effect of doing an (ignored) read though. >Unfortunately I don't think specifying bus semantics is within the >purview of the ANSI committee (please correct me if I'm wrong - my >knowledge of the details of the standard is limited) and volatile is >not sufficient to force the desired activity. Fortunatly you are wrong, and volitile is sufficient. -- Bob Larson Arpa: Blarson@Ecla.Usc.Edu blarson@skat.usc.edu Uucp: {sdcrdcf,cit-vax}!oberon!skat!blarson Prime mailing list: info-prime-request%ais1@ecla.usc.edu oberon!ais1!info-prime-request
desnoyer@Apple.COM (Peter Desnoyers) (12/06/88)
In article <13784@oberon.USC.EDU> blarson@skat.usc.edu (Bob Larson) writes: >In article <21560@apple.Apple.COM> desnoyer@Apple.COM (Peter Desnoyers) writes: >>pet peeve - It is a common thing to have to write a zero to a device >>register. The obvious code, (* reg_addr) = 0, often results in: >> >> xor reg_addr, reg_addr > >What machine is this for? I'm pretty sure Turbo C on the PC does this. Even with optimization off. I'll check. >Most 68000 compilers would use the >clr instruction, which does have the undesired side effect of doing >an (ignored) read though. > Almost as bad. The important point is that if these micro-optimizations are performed in the compiler pass of a pre-ANSI compiler, there is NO way to turn them off. Thus the naive view that everything worked fine before ANSI started messing with the language is demonstrably wrong. >>...(please correct me if I'm wrong ... [whether volatile specifies >>one write and no reads] I stand corrected. Thank you. Peter Desnoyers
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/06/88)
First of all I wish to admit I have been inaccurate; as somebody remarked "noalias" was only briefly in the dpANS C, and "far" and "near" never actually made it in the official documents sent out for review. But all were for a long time in various drafts, and as usually happens people actually advertised "far" and "near" as examples of draft, unofficial ANSI C conformance. Thank goodness X3J11 frustrated their efforts in the end. In article <225@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes: In article <277@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: : As I understand it, this means that char,short,int,long are distinct : types, whereas unsigned and signed are type modifiers. In a sense then, : the view of dpANS is that unsigned [int] and [signed] int are the same : type, only that one has a sign and the other hasn't. If you want to, you can think of this as types and modifiers, though the standard does not speak of them that way. If so, here is how you do it: The types: char int That's right. Only two. The modifiers: unsigned signed short long The first pair modifies char or int; the second int only. You can specify only one of each pair. OK, the standard does not speak of modifiers and types, but then the result is the long lists you give and lots of confusion. I think there are two issues here, one the introduction of signed as a keyword, and the other neat ways of defining semantics. As to the latter, the whole type system would be greatly simplified if one were to say that [1] there are two distinct types, int and unsigned; they are distinct types because different rules of arithmetic apply to them. This would make it clear, and I have found very few people that actually understand that unsigned is not just "positive int", that the same operators applied to int and unsigned have very different semantics. [2] Each of the two distinct types may come in three different extra lengths, char, short and long, that are exactly equivalent among them for the same type except for the different size. As to the last point, char has been so far just a short short; a char value can be operated upon exactly as an integer. Historically char constants have been really the size of integer constants... I would have liked, instead of the unnecessary and confusing signed modifier, a nice range(abs_max) modifier for types integer and unsigned, and char/short/long defined in terms of it. This would have added tremendously to the portability of programs. The lack of some sort of ranges and the use of short and long are one of the few things I dislike in Algol68 and C. I hope such an interesting extension makes it into C++, or at least into the GNU C++ compilers (hint hint Michael Tiemann!). There is no relationship between char and signed or unsigned char, other than that they occupy the same amount of storage. Now I reiterate the question: why was a new keyword introduced "signed" when it just sufficed to sanction the existing practice of some compilers (PCC had it, more recent BSD versions fixed this "bug") to say "int char" or better "char int"? Since storage classes, modifiers, and type names could be given in any order in a declaration; most compilers therefore simply collected keywords, and set a flag in the symbol table entry for the variable for each keyword they collected. This meant that "int static char int static" was accepted as a legal declaration by many compilers :-). This has been later often "corrected", notably in 4BSD pcc. Amusingly it persists even today in other compilers, among them g++ 1.27, where interestingly "sizeof (char int)" is 4 and "sizeof (int char)" is 1 on a 68020... Of course in my opinion both ought to be 1, or an order storageclass/modifier/type might be enforced, making "int char" illegal and "sizeof (char int)" equal to 1. -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/07/88)
In article <330@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >First of all I wish to admit I have been inaccurate; as somebody remarked >"noalias" was only briefly in the dpANS C, and "far" and "near" never >actually made it in the official documents sent out for review. But all >were for a long time in various drafts, and as usually happens people >actually advertised "far" and "near" as examples of draft, unofficial >ANSI C conformance. Thank goodness X3J11 frustrated their efforts in the end. You're still inaccurate. "far" and "near" were never at any time in any draft of the proposed ANSI C standard. "noalias" was not in any draft other than the one sent out for the second public review. How could it be, when it had just been invented at the previous meeting and was retracted at the next? Are you just making this stuff up, or do you have drug-using advisors, or what? >As to the last point, char has been so far just a short short; a char >value can be operated upon exactly as an integer. Except that whether it acts as signed or unsigned depends on the implementation. >Historically char constants have been really the size of integer >constants... You mean "character constants"; in C they ARE integer constants specified in a certain character-oriented way. >Now I reiterate the question: why was a new keyword introduced "signed" >when it just sufficed to sanction the existing practice of some >compilers (PCC had it, more recent BSD versions fixed this "bug") to >say "int char" or better "char int"? I have never seen a C compiler that accepted "int char"; certainly Ritchie didn't intend for it to be valid. Also, char has never been guaranteed to be signed; read K&R 1st Edition. It happened to be most efficient on the PDP-11 to make it signed, but it was implemented as unsigned on some other architectures. The VAX port of the C compiler could have done it either way; signed behavior was chosen, presumably to aid in porting code developed on the PDP-11. The IBM 370 and WE 3B compilers had chars act as unsigned all along. Ritchie specifically blessed this implementation dependence in his BSTJ article on C in 1978. >Amusingly it persists even today in other compilers, among them >g++ 1.27, where interestingly "sizeof (char int)" is 4 and "sizeof >(int char)" is 1 on a 68020... I don't know what C++ rules for basic types really are, but if as I suspect g++ is getting it wrong, you should report this bug to the GNU project.
ray@micomvax.UUCP (Ray Dunn) (12/08/88)
In article <10919@ulysses.homer.nj.att.com> ggs@ulysses.homer.nj.att.com (Griff Smith) writes: >.... >I agree, and I don't object, but some brief encounters with an ANSI >compiler make me worry about it a bit. The problem is that the >existence of the volatile qualifier makes it possible to do >optimizations that were previously forbidden (or at least difficult to >slip past the customers). I blew several hours discovering that a flag >set by a signal handler had been optimized out of existence because it >wasn't declared volatile. There is the implication here that the introduction of the "volatile" qualifier is the *cause* of the problem. This is of course not true, the qualifier is an attempt to provide a *solution* to the problem. Many existing pre-ANSI compilers will optimize away memory references that are in fact required because the variable is "volatile" but the compiler has no way of knowing. In pre-ANSI 'C', *all* variables are regarded as being *non-volatile*, the compiler is free for example to keep the variable in a register, and there is usually no way to selectively stop the compiler optimizing their references away. You usually can turn off optimizations globally while compiling a module. One technique to use is to collect all fucntions containing volatile stuff into one or more modules, and only compile *them* with optimisation off. The "volatile" qualifier is a *much* better solution when you have an ANSI Conforming compiler. -- Ray Dunn. | UUCP: ..!philabs!micomvax!ray Philips Electronics Ltd. | TEL : (514) 744-8200 Ext: 2347 600 Dr Frederik Philips Blvd | FAX : (514) 744-6455 St Laurent. Quebec. H4M 2S9 | TLX : 05-824090
bill@twwells.uucp (T. William Wells) (12/08/88)
In article <330@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes:
: I think there
: are two issues here, one the introduction of signed as a keyword, and
: the other neat ways of defining semantics. As to the latter, the whole
: type system would be greatly simplified if one were to say that
`Signed' is there so that we can have `signed char'. As to why one
would want that, the original C specified that, while a char was an
integer, whether it could contain negative values is up to the
implementer. `Signed char' has the same size as a char, but it is
always signed. (And yes, there are good reasons not to change the
current definition of `char').
`Signed' was then allowed as a modifier for the other types, for
reasons of symmetry.
(This is all in the Rationale, in section 3.1.2.5.)
As for simplifying the type system; the current one is as simple as
is possible for it to be, given that it *must* be compatible with the
old one, and given the addition of a `signed char'.
: [1] there are two distinct types, int and unsigned; they are distinct
: types because different rules of arithmetic apply to them. This would
: make it clear, and I have found very few people that actually
: understand that unsigned is not just "positive int", that the same
: operators applied to int and unsigned have very different semantics.
Then you have simply been hanging around inexperienced C programmers.
Not only that, but you are wrong about there being two distinct
types; from the view you are adopting, there are three. See below.
: [2] Each of the two distinct types may come in three different extra
: lengths, char, short and long, that are exactly equivalent among them
: for the same type except for the different size.
This would be nice if it were compatible with history; however...
: As to the last point, char has been so far just a short short; a char
: value can be operated upon exactly as an integer. Historically char
: constants have been really the size of integer constants...
This is false. Char has not been and ought not be made just a short
short. Char is a funny type. It is neither signed nor unsigned though
it is always implemented as one or the other.
Let me repeat this: there are three signednesses in C:
1) integers - these have positive and negative values.
2) unsigned - these have positive values only.
3) char - these have positive values. Sometimes they have
negative values as well but it depends on the implementation.
: I would have liked, instead of the unnecessary and confusing signed
: modifier, a nice range(abs_max) modifier for types integer and
: unsigned, and char/short/long defined in terms of it. This would have
: added tremendously to the portability of programs.
And here again you are wrong. While it is sometimes nice to be able
to specify numeric ranges, it is hardly necessary to do so for
portability. Understanding the C paradigm, one can use the existing
types to create portable code. I do it all the time; my code is
regularly ported to everything from micros to mainframes.
: to sanction the existing practice of some
: compilers (PCC had it, more recent BSD versions fixed this "bug") to
: say "int char" or better "char int"?
`Char int' is, and always has been, illegal. I don't know of a single
compiler that accepts it. I just checked: the one on my system
(Microport, a system V) and the one on my work machine (SunOS,
more-or-less BSD) reject it. I believe that both are based on the
PCC. I know that the C compiler (from ISC) we used on our PDP-11 and
our VAX, between four and six years ago, both rejected `char int' and
similar constructs. I'm almost certain that both compilers were PCC
based.
---
Let me suggest that you should carefully read the various books on C,
starting with K&R (the original), the Harbison & Steele book, and
some other good C textbooks. *Then* read the latest draft of the C
standard. Do all of this without reference to what you would wish
the language to be. Understand what it *is*; develop familiarity with
the paradigms and facts of the language. Then, and only then, will be
you be equipped to complain about C's deficiencies.
In the mean time, I'm going to stop responding to your statements
about what C ought to be. You have formed these opinions in the
absence of knowledge; I have come to believe that I am wasting my
time trying to correct them.
If you have questions about the language, go ahead and ask them, and
you'll even get a civil reply, but please stop telling us what the
language should be until you know what it *is*.
---
Bill
{uunet|novavax}!proxftl!twwells!bill
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/10/88)
In article <1450@micomvax.UUCP> ray@micomvax.UUCP (Ray Dunn) writes: In article <10919@ulysses.homer.nj.att.com> ggs@ulysses.homer.nj.att.com (Griff Smith) writes: >The problem is that the >existence of the volatile qualifier makes it possible to do >optimizations that were previously forbidden (or at least difficult to >slip past the customers). They were not forbidden, you could do any optimization that did not impact the semantics of programs. A Classic C program compiled with a dpANS C compiler changes semantics, unless you tag with volatile all variables not tagged register. There is the implication here that the introduction of the "volatile" qualifier is the *cause* of the problem. This is of course not true, the qualifier is an attempt to provide a *solution* to the problem. It IS the cause! volatile is not necessary, register is sufficient... I have tried to give arguments for this (at length :->). In pre-ANSI 'C', *all* variables are regarded as being *non-volatile*, the compiler is free for example to keep the variable in a register, and there is usually no way to selectively stop the compiler optimizing their references away. Exactly the opposite! In Classic C the concept was that the compiler would take register as an hint of which variables could always be safely cached in register (and the user be forbidden to take pointer to them), and all the others could be cached only if it was guaranteed that doing so would not "cause surprises". You usually can turn off optimizations globally while compiling a module. One technique to use is to collect all fucntions containing volatile stuff into one or more modules, and only compile *them* with optimisation off. Think again. You REALLY want the semantics of your code dependent on the flags you give to a compiler? The "volatile" qualifier is a *much* better solution when you have an ANSI Conforming compiler. Actually it is a backwards step wrt to register, as it encourages bloated compilers and the delusion that they can select which variables to put in registers better than you can do, while requiring careful analysis as to which variables MUST be declared volatile (as failing to tag them makes your program erroneous, where register is perfectly safe). -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
gwyn@smoke.BRL.MIL (Doug Gwyn ) (12/11/88)
In article <369@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >They were not forbidden, you could do any optimization that did not impact >the semantics of programs. A Classic C program compiled with a dpANS C >compiler changes semantics, unless you tag with volatile all variables not >tagged register. This, as with practically everything else Grandi has said about C, is simply not true. There are a few fairly subtle changes in the semantics going from K&R 1st Ed. C to ANSI C, for example mixed type promotion in expressions and linkage rules, but they affect few programs. There was never a guarantee that C data had what is now known as the "volatile" property. Existing compilers in fact give the lie to such a claim. >Exactly the opposite! In Classic C the concept was that the compiler would >take register as an hint of which variables could always be safely cached in >register (and the user be forbidden to take pointer to them), and all the >others could be cached only if it was guaranteed that doing so would not >"cause surprises". Please cite references for this unique notion of what pre-ANSI C's rules were. So far as I have been able to determine, it was never specified one way or another, so by the usual rules for interpreting C rules, this would have been an unwise assumption to make. (Particularly since existing implementations did not follow that rule.) >Actually it is a backwards step wrt to register, as it encourages bloated >compilers and the delusion that they can select which variables to put in >registers better than you can do, while requiring careful analysis as to >which variables MUST be declared volatile (as failing to tag them makes >your program erroneous, where register is perfectly safe). "register" is still a supported specifier under ANSI C. Use it if you think your compiler does a poor job of register allocation. The use of "volatile" does not require much analysis. If you were paying attention, I already explained in response to Griff Smith the cases where you need to use it. In pre-ANSI C the same problem existed, but there was no standard solution for it.
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/12/88)
I realize that in my crudeness and brutality there is no hope for me to achieve the extremely rarified levels of wisdom and learning of certain people endowed with a quick grasp of issues and gentlemany manners of debate. I therefore appeal (bowing my head, palms joined :->) to higher authority. Let me quote and summarize from one such easily recognizable higher authority, and repeat my own contentions (if it is boring for you, think how it is for me): ----------------------------------------------------------------------------- # 4. What's in a name [ .... ] # Objects declared as characters ("char") are large enough to store any # member of the implementation's character set, and if a genuine character # from that character set is stored ina character variable, its value is # equivalent to the integer code of that character. Other quantities may be # stored in a character variable, but the implementation is machine # dependent. character type == an integer type of sufficient length, whether "unsigned" or "int" is up to the implementation. # Up to three sizes of integer, declared "short int" "int", and "long int" # are available. [ .... ] integer type == any one of the three lengths of "int", not just "int". # Unsigned integers, declared "unsigned", obey the laws of arithmetic # modulo "2^n", where "n" is the number of bits in the representation. (on the # PDP-11, unsigned long quantitied are not supported). unsigned integer type == "unsigned" integer of all lengths, except of the PDP-11. Semantics are different from thsoe of integer types, as they obey the rules of modular, not algebraic, arithmetic. # [ .... ] Because objects of the foregoing types can be usefully interpreted # as numbers, the will be referred to as "arithmetic" types. Types "char" and # "int" of all sizes will be collectively called "integral" types. [ .... ] character type == "char", some large enough integer or unsigned integer type; unsigned integer type == "unsigned" of all lengths; integer type == "int" of all lengths (occasionally includes also "unsigned"s); integral type == all three of them. arithmatic type == integral types plus all lengths of "float". # 6.1 Characters and integers # A character or a short integer may be used whenever an integer is used. # In all cases the value is converted to an integer. There is no behavioural difference between char, short and other lengths of "int", but for their range. # Conversion of a shorter integer to a longer always involves sign # extension; integers are signed quantities. Integer types involve sign extension, by contrast with unsigned integer types. # Whether or not sign extension occurs for characters is machine dependent, # [ .... ]. Whether or not "char" is an integer or unsigned integer type is not prescribed. # [ .... ] When a longer integer is converted to a shorter or to a "char", # it is truncated on the left; excess bits are simply discarded. There is no behavioural difference between "char" and "short", or other lengths, except their size. # 6.5 Unsigned # Whenever an unsigned integer and a plain integer are combined, the # plain integer is converted to unsigned and the result is unsigned. # The value is the least unsigned integer congruent to the signed # integer (module "2^wordsize"). [ .... ] When an unsigned integer is # converted to "long", the value of the result is the same numerically # as that of the unsigned integer. [ .... ] The rules for conversions involving unsigned integers are different from those for integers. # 7. Expressions [ .... ] # The handling of overflow and divide check is expression evaluation is # machine dependent. [ .... ] Note insofar overflow is concerned this only applies to integer types, as unsigned integer types cannot overflow by definition. In other words, exceeding the range of a length of "int" is not well defined, while exceeding the range of a length of "unsigned" is. Another case where there are behavioural differences between unsigned integer and integer types. # 7.2 Unary operators # [ .... ] The result of the unary "-" operator is the negative of its # operand. The usual arithmetic conversions are performed. The negative of # an "unsigned" quantity is computed by subtracting its value from "2^n", # where "n" is is the number of bits in an "int". [ .... ] Another case where there are behavioural differences between unsigned integer and integer types. # 7.5 Shift operators # [ .... ] The right shift is guaranteed to be logical (0 fill) if "E1" # is "unsigned"; otherwise it may be (and is, on the PDP-11), arithmetic # (fill by a copy of the sign bit). Another case where there are behavioural differences between unsigned integer and integer types. # 8.2 Type specifiers # [ .... ] The words "long", "short" and "unsigned" may be thought of as # adjectives; the following combinations are acceptable: [ .... ] Here lies the crux of the matter. Throughout it is repeatedly and explicitly stated that unsigned integer types behave differently from integer types, and that the character type does not behave differently from a sufficiently long/short unsigned integer or integer type. Given this and the quoted phrase, it is apparent in hindsight that syntax and semantics are incomplete, as there is no way to ensure the signedness of a "char" (a similar problem exists with bit fields), and that syntax does not properly reflect semantics. dpANS C addresses the first point only, adding the "signed" keyword that can thought of as another adjective and adding several cases to the table of acceptable combinations. My contentions (for the last time!) are that [1] this is not necessary, as it is more natural to drop the pretense that "char" is a type distinct from "int", and instead adopt the notion that "char" is like "short", an adjective that modifies the length of its base type; [2] it does not resolve the issue of making clear that "unsigned" is semantically different from "int", while the various lengths of either type are, but for the different ranges, semantically equivalent among themselves, and this distinction is important; [3] both points can be economically addressed by redefining as integral types the class of all integer and unsigned types, as integer types the various lengths of "int", as unsigned types the various lengths of "unsigned", and as length adjectives/modifiers the keywords "char", "short", "long"; when the adjective is omitted, the base type has the length of "short" or "long", depending on the implementation; when the base type type is omitted, "int" is presumed, except for length "char", where the choice is implementation dependent. [4] the proposed rationalization, provided that "unsigned int" is made as a special case equivalent to "unsigned", is backward compatible; [5] because of a easily made "mistake", some compilers, in the past or now, did not/do complain when the rationalized syntax was/is used, and this could be easily blessed instead of eradicated; [6] if it is felt desirable to substantially modify the declaration of "int" or "unsigned" types, a new keyword could be introduced for range definition, or the syntax for bit fields could be allowed outside ------------------------------------------------------------------------- Kind reader, having had the patience to reach this point, make a last effort, and please circle what you believe to be the correct answers: [1] The material quoted above: [A] Is excerpted in an accurate, substantial and non misleading way from "The C programming Language - Reference Manual" (1978) the authoritative definition of Classic C. [B] I have made it up. [2] The summaries I have made of the various passages quoted: [A] Accurately reflect the contents of said Reference Manual, or at least a consistent and historically defensible interpretation of those contents. [B] I have never read/understood the Reference Manual. [3] The final contentions and suggestions are: [A] Supported by fair and reasonable technical arguments, based on the contents of said Reference Manual, as well as other more mundane points. [B] My advisor (if I had one) must be on drugs. -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/12/88)
It seems that my problem with Doug Gwin is that he cannot conceive that his rationales can be doubted: if you want signed characters, the only way is to add a signed keyword, if you want efficient code the only way is a complex optimizer that relies on volatile. Since he cannot believe that there can be other approaches, he cannot help assuming that I have not understood his premises, because my conclusions are different. The problem is that I am fully aware of his premises, and still I have different ones. In article <9143@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: There was never a guarantee that C data had what is now known as the "volatile" property. You mean that nobody explicitly stated the obvious rule that an optimizer shall not turn a correct program into in incorrect one? Of course! As I said, C was not designed for optimizing compilers; it was designed as a low level language, and the very idea that an optimizer could do nasty things behind the programmer's back was unthinkable. C is indeed virtually unique in having the register keyword (other languages allow you to assign variables to specific registers or memory locations, notably Ada, LIS, Modula-2, Mesa?, but C's register is not like that, of course), by which the programmer helps the compiler, precisely because the compiler is not expected assumed or required to have or need an optimizer. The point here is not to ASSUME that nasty optimization is necessary and legitimate (and then indeed volatile become necessary to cover your back) the point is to DEFEND the philosophy under which nasty optimization is necessary in a language like C that was consciously designed with quite different assumptions and goals (ever heard this about UNIX and C : simple is beutiful AND reliable AND easier AND faster AND... or are you a post-V7 guy? :->). Also, given your belief that Classic C did not explicitly prohibit wanton caching of non register variables, well, this was what dpANS C ought to be about, closing loopholes, clarifying that it was never explicitly forbidden because it was never thought necessary, encouraging the use of register. NOT introducing volatile. X3J11 has indeed done a fine job in most other areas on clarifying, closing loopholes, etc... Existing compilers in fact give the lie to such a claim. Then they are buggy! I would like to remind you that C is not what you think it to be (a close cousin of Ada, a son of BSD), it is what has been defined to be and used for years and years before a lot of commercial interests saw a competitive advantage in claiming their compiler would improve sloppy C code; the world does not begin with dpANS, or with 4.xBSD/S5.x. Please cite references for this unique notion of what pre-ANSI C's rules were. So far as I have been able to determine, it was never specified one way or another, so by the usual rules for interpreting C rules, this would have been an unwise assumption to make. (Particularly since existing implementations did not follow that rule.) Again, it has never been a usual rule that an optimizer is allowed to turn a correct program into an incorrect one. If an existing implementation does it, it is buggy. This volatile argument is as old as programming; every PL/1 programmer knows that many a compiler will generate buggy code when the optimizer is let loose on code with exception handlers. They do not think that that is a fault of the language, they rightly think that it is the compiler that is wrong, and they greatly resent having to use a compiler option to influence the semantics of a piece of code (ahhhh, if only PL/1 included volatile for variables, instead of only for procedures! :->). "register" is still a supported specifier under ANSI C. Use it if you think your compiler does a poor job of register allocation. But in any case I still must volatilize all other variables, otherwise the compiler will do funny things behind my back. Volatile and register are constrasting approaches to solve the same problem, one is safe and does not suggest that a complex optimizer is needed, the other is potentially unsafe and deludes people into buying complex, often unreliable compilers for a language that was carefully evolved and designed not to require them (and therein lies one of its beauties, maybe the most important -- otherwise we would be using Ada or PL/1). Volatile encourages people to think that a complex optimizer will clean up their sloppy C code. Too bad that the cleanup cannot be as good as competently written code, that omitting volatile where it is needed results in very hard to find bugs, that complex optimizers are themselves, for obvious reasons, often very buggy. The use of "volatile" does not require much analysis. If you were paying attention, I already explained in response to Griff Smith the cases where you need to use it. My dear Doug Gwin, rest assured that your paternalistic innuendo is not necessary. I know perfectly well the rationale for "volatile" (enable optimizations where side effects may occur); I dispute that the only solution to the problem is "volatile", as I dispute the rationale itself. I would also like to emphasize that the real big problem will be multi threaded C code, not signal handlers or device drivers. As any Ada programmer knows, if you use tasking and fail to stick pragmas volatile/shared wherever they are needed, maybe in dozens of modules, and that may be a lot of places, you get into BIG trouble. In pre-ANSI C the same problem existed, but there was no standard solution for it. The problem did not exist, because it was unthinkable that the compiler would do funny things behind your back! If it did, the solutions were: Debug the compiler! Or, if you could not do that, wrap the reference to the variable around an asm procedure (which is usually necessary anyway in device drivers to correctly access device registers, as compilers cannot give the guarantee that they will generate the exactly right code), as procedures are all considered "volatile" (in C and almost all other languages I know -- several dozen -- except PL/1 and some AI/Lispish ones). I would like to add a note (hope it does not start another stream of misunderstanding, misrepresentation and abuse towards me :->) I would like to be able (maybe in C++ ?) to declare a procedure as "register", to signify that the values it returns only depend on the arguments and not on any globals, and thus it will always return the same values given the same arguments. Apart from giving a very clever (that, as I said, I do not like) compiler a good opportunity to do some caching of procedure's results, it would be extremely useful to a mechanical (lint?) or human reader/verifier of the code, as it would clearly document which procedures are functions and which are generators/closures, an extremely important distinction. -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
henry@utzoo.uucp (Henry Spencer) (12/14/88)
In article <369@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >... In Classic C the concept was that the compiler would >take register as an hint of which variables could always be safely cached in >register (and the user be forbidden to take pointer to them), and all the >others could be cached only if it was guaranteed that doing so would not >"cause surprises". Please cite references for this. It's never been true. -- SunOSish, adj: requiring | Henry Spencer at U of Toronto Zoology 32-bit bug numbers. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
ok@quintus.uucp (Richard A. O'Keefe) (12/14/88)
In article <375@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >My contentions (for the last time!) are that > > [1] this is not necessary, as it is more natural to drop the pretense > that "char" is a type distinct from "int", and instead adopt the notion > that "char" is like "short", an adjective that modifies the length of its > base type; > That change would *FORCE* compiler writers to break working code. There are programs which were written for machines with unsigned chars (predating the introduction of 'unsigned char') where the programmers relied on the char range being 0..255. While this was not _portable_, that implementation was _permitted_. If you now rule that char = char int and is *signed* then to conform to the standard, compiler writers for those machines would _have_ to make plain chars signed. The method X3J11 chose _allows_ compiler writers for those machines to keep their old semantics for plain 'char', and thus lets them offer backwards compatibility to their customers. It simply wasn't possible to make the new standard compatible with all the old compilers, but X3J11 didn't introduce incompatibility lightly. Don't forget, the signed/unsigned ambiguity of 'char' was provided in the first place for very practical reasons: there are machines where signed chars are more efficient, and there are machines where unsigned chars are more efficient. That is still true, so we _still_ want a way of saying "whichever of signed byte/unsigned byte is cheaper, I promise not to care". To be perfectly frank, I don't expect to have any use for 'signed char'. I particularly don't want all my programs which use 'char' (because I wanted the efficiency and didn't need a large range) to be forced to use signed bytes, so the "char = char int = signed char" rule, while it would not _break_ my programs, would definitely make them less efficient. NO THANK YOU!
wald-david@CS.YALE.EDU (david wald) (12/15/88)
In article <377@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >You mean that nobody explicitly stated the obvious rule that an optimizer >shall not turn a correct program into in incorrect one? Of course! As I said, >C was not designed for optimizing compilers; it was designed as a low level >language, and the very idea that an optimizer could do nasty things behind >the programmer's back was unthinkable. and: >Again, it has never been a usual rule that an optimizer is allowed to turn a >correct program into an incorrect one. If an existing implementation does it, >it is buggy. This volatile argument is as old as programming; every PL/1 >programmer knows that many a compiler will generate buggy code when the >optimizer is let loose on code with exception handlers. You twice invoke this rule that "an optimizer shall not turn a correct program into an incorrect one," and I have yet to see someone hint that this statement is false. But I have still not seen any supporting references for your view of what constitutes "correctness." Your view seems to be that all variables are volatile unless declared register, and you assert that this was the intention of the "register" keyword. K&R's statement of the meaning of register is "A register declaration advises the compiler that the variable in question will be heavily used. When possible, register variables are placed in machine registers, which may result in smaller and faster programs." [4.7] Clearly, the intent is to allow the optimization of placing the most heavily used variables in processor registers. Similarly, A register declaration is best thought of as an auto declaration, together with a hint to the compiler that the variables declared will be heavily used. Only the first few such declarations are effective. Moreover, only variables of certain types will be stored in registers....[Appendix A, 8.1] As for your suggested use of "register," (i.e., saying "not volatile"), I fail to see how this purpose is served if "only the first few such declarations are effective." Further, the semantic distinctions you refer to between "register" and "auto" variables merely reflect the realities of registers on many architectures: "In practice, there are some restrictions on register variables, reflecting the realities of underlying hardware. Only a few variables in each function may be kept in registers, and only certain types are allowed. The word register is ignored for excess or disallowed declarations. And it is not possible to take the address of a register variable.... The specific restirictions vary from machine to machine....[4.7] In this context, the rule about taking the address of a register variable appears simply as an afterthought, due to the PDP-11 architecture, rather than an essential aspect of the semantics. Finally, with regard to your comments about the place of optimizing compilers in C: "Smaller, faster programs can be expected if register declarations are used appropriately, but future improvements in code generation may render them unnecessary" [Appendix A, 8.1] Thus anticipating the future obsolesence of "register" as optimizers improve. If K&R is not a good sign of the original intent of a keyword, what are you using as your authority? ============================================================================ David Wald wald-david@yale.UUCP waldave@yalevm.bitnet ============================================================================
henry@utzoo.uucp (Henry Spencer) (12/15/88)
In article <377@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: > There was never a guarantee that C data had what is now known as the > "volatile" property. > >You mean that nobody explicitly stated the obvious rule that an optimizer >shall not turn a correct program into in incorrect one? ... No, that's not what he meant: he meant that your definitions of "correct" and "incorrect" are historically wrong, and do not correspond to the way C was defined, implemented, and used. Very little has ever been guaranteed about how C programs are evaluated, although some C programs (notably the Unix kernel) have quietly relied on the limitations of old compilers. ANSI C actually considerably strengthens the guarantees made to the programmer. Might one ask how long you have been using C, Mr. Grandi? -- "God willing, we will return." | Henry Spencer at U of Toronto Zoology -Eugene Cernan, the Moon, 1972 | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
guy@auspex.UUCP (Guy Harris) (12/15/88)
>It seems that my problem with Doug Gwin is that he cannot conceive that his >rationales can be doubted: if you want signed characters, the only way is >to add a signed keyword, if you want efficient code the only way is a complex >optimizer that relies on volatile. Err, umm, first of all, that's "Gwyn", not "Gwin", as you can check the attribution line in your posting. Second of all, you appear also not to conceive that the notion that C is a language whose compilers shouldn't optimize can be doubted, either. To put it bluntly, that's rubbish. There are plenty of people out there who can, I suspect, testify that yes, indeed, optimizing C compilers *can* produce better code than non-optimizing ones, *even when the C source is, in some sense, "good" code.* As such, statements such as: >You mean that nobody explicitly stated the obvious rule that an optimizer >shall not turn a correct program into in incorrect one? Of course! As I said, >C was not designed for optimizing compilers; it was designed as a low level >language, and the very idea that an optimizer could do nasty things behind >the programmer's back was unthinkable. are unlikely to be very convincing to a large (and, I suspect increasing) portion of the audience. Sorry, but the notion that "the very idea that an optimizer could do nasty things behind the programmer's back was unthinkable" isn't as widely accepted as you appear to wish it to be - and, I suspect, never was - and just because some people *assumed* that the compiler generated "straightforward" code doesn't mean 1) it was true in most implementations or 2) it was to be taken in any way to be a guarantee. By and large, your arguments on "volatile", etc. amount to "C was always supposed to be a language whose compilers did little optimization, and C compilers shouldn't do lots of optimization, period." Merely stating this premise repeatedly isn't going to convince a lot of us, because we've seen quite good C code turned into better code with a high-power optimizer on than with it off (and no, simply declaring that that code must therefore not have been very good isn't going to convince us, either). Please try another approach, preferably one involving hard data showing that good *and* readable C code *doesn't* get turned into significantly better code when run through a compiler with a more powerful optimizer than when run through a more "straightforward" compiler - and showing this in a reasonable range of modern architectures, including (but not limited to!) modern RISC architectures. "Proof by blatant assertion" isn't good enough.
ok@quintus.uucp (Richard A. O'Keefe) (12/16/88)
In article <377@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >This volatile argument is as old as programming; every PL/1 >programmer knows that many a compiler will generate buggy code when the >optimizer is let loose on code with exception handlers. >They do not think that that is a fault of the language, they rightly think >that it is the compiler that is wrong, and they greatly resent having to use >a compiler option to influence the semantics of a piece of code (ahhhh, if >only PL/1 included volatile for variables, instead of only for procedures! :->). (a) It's PL/I, not PL/1. (b) PL/I *does* include "volatile" for variables. There are two pairs of attributes: IRREDUCIBLE/REDUCIBLE and ABNORMAL/NORMAL. The default in PL/I is as in dpANS C: if you do not explicitly say otherwise the compiler will assume a variable is _not_ "volatile".
ray@micomvax.UUCP (Ray Dunn) (12/17/88)
In article <369@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >In article <1450@micomvax.UUCP> I wrote: > > This is of course not true, the qualifier is an attempt to provide a > *solution* to the problem. > >It IS the cause! volatile is not necessary, register is sufficient... >I have tried to give arguments for this (at length :->). >....etc. etc. etc.... Sigh... It's not easy to come to a conclusion when each side is discussing totally different subjects! I'm talking about 'C', Mr. Grandi appears to be talking about some strange set of ad hoc rules which are figments of his fertile imagination. As several people have now said Piercarlo, your conceptions of what 'C' defines on both this question of "volatile", and of associating signedness to the word "int" amongst other things, are imaginary. Please go back and *absorb* the 'C' spec again, from the ground up. I hope I have managed to refrained myself from escalating this into a flamefest.... -- Ray Dunn. | UUCP: ..!philabs!micomvax!ray Philips Electronics Ltd. | TEL : (514) 744-8200 Ext: 2347 600 Dr Frederik Philips Blvd | FAX : (514) 744-6455 St Laurent. Quebec. H4M 2S9 | TLX : 05-824090
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/18/88)
In article <860@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes:
[ on my suggestion to make "char int" denote guaranteed signed chars ]
That change would *FORCE* compiler writers to break working code.
Why ever? I have never advocated removing the rule that "char" by itself is
either "int" or "unsigned", merely added a way to guarantee that it would be
signed.
There are programs which were written for machines with unsigned chars
(predating the introduction of 'unsigned char') where the programmers
relied on the char range being 0..255. While this was not _portable_,
that implementation was _permitted_. If you now rule that
char = char int and is *signed*
Never implied this. (I care about backwards compatibility, even if I don't
like it where is rewards, like in your example, non portable practices).
but X3J11 didn't introduce incompatibility lightly.
Yet it introduced an unnecessary keyword, the perpetuates the unfortunate
syntax that favors the confusions that "char" is indeed a type and "unsigned"
is indeed just a variant of "int".
[ .... ] we _still_ want a way of saying "whichever of signed
byte/unsigned byte is cheaper, I promise not to care".
Indeed!. Since 'char' is to be a length modifier, I assumed it was obvious
that in case the base type is missing, it would default to either 'int' or
'unsigned', while for all other length modifiers it would always default to
'int'.
In dpANS C the rule is conversely that the type modifier 'signed' is the
default for all the lengths of 'int', but not for type 'char' where the
default may be either 'signed' or unsigned'.
To be perfectly frank, I don't expect to have any use for 'signed char'.
I have, I have! (I mean "char int" of course). In many many cases one wants
to really consider "char" a length specifier, and create arrays of byte sized
integers or unsigneds (or don't cares).
--
Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk
Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg
UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/18/88)
In article <1988Dec15.005828.1874@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >You mean that nobody explicitly stated the obvious rule that an optimizer >shall not turn a correct program into in incorrect one? ... No, that's not what he meant: he meant that your definitions of "correct" and "incorrect" are historically wrong, As somebody else has remarked to you, in the classic era of C, long since dead, it was *unthinkable* that the compiler would be much more than a clever translator. Also, AT&T C compilers *did* define for a long time what C was... After all, the Ritchie PDP-11 compiler was known as the "Standard C Compiler" for some reason, wasn't it? Now, we all agree that language definitions *should not* depend on particular implementations, and in clarifying many issues X3J11 has considerably improved matters on this, but here we are discussing history and rationales. Register, +=, ++, are all sure signs that C was meant to be compiled by a simple compiler that relied on the programmer to use such constructs to help code generation. and do not correspond to the way C was defined, Just a moment. Ritchie never explicitly did allow aggressive optimization. So, at the very least, your argument that it was allowed by default, and my own that it was disallowed by default, are matters of opinion. But, but I support my opinion by argument, as always. Ritchie introduced "register" in Classic C, not "volatile", after all, and this *means* something. If he had meant aggressive optimization to be allowed, he might not have introduced "register"; he would have surely deemed "volatile" absolutely necessary, the more so as he used C to write, of all things, Unix's device drivers. implemented, and used. On PCs, on PCs... Might one ask how long you have been using C, Mr. Grandi? Regularly, since 1980 (of course I had already bought K&R as soon as it was out). Probably my main impulse in extolling the virtues of Classic C is therefore plain old nostalgia for the good ol' days of V7 Unix and C... (on a Onyx with V7, or an 11/34 with 2.9BSD). I still keep in my office a photograph of the 11/34 (248KB, 80MB disk, I used to have five concurrent users with good performance). -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/18/88)
In article <45697@yale-celray.yale.UUCP> wald-david@CS.YALE.EDU (david wald) writes: K&R's statement of the meaning of register is [ .... quotes from K&R that form the basis of MY argument .... ] As for your suggested use of "register," (i.e., saying "not volatile"), I fail to see how this purpose is served if "only the first few such declarations are effective." Hey, here we start to read different thing. I read that "effective" refers to putting things into registers, not to the register keywords itself. Even if a register variable is not in fact held in a register (either because they have all been allocated or the type is not suitable) this does not mean that the register keyword is being ignored; on the contrary, you still cannot take its address, for example. "register" contains a hint, and it is the hint that may or not be effective, not the keyword. Further, the semantic distinctions you refer to between "register" and "auto" variables merely reflect the realities of registers on many architectures: Realities that are not "mere"; they are quite important to portability. In this context, the rule about taking the address of a register variable appears simply as an afterthought, I think it is the very core of the beauty of the idea of "register". due to the PDP-11 architecture, rather than an essential aspect of the semantics. I disagree. First, *many* architectures do disallow pointers to registers, so it was natural to introduce the restriction for the sake of portability. Second, there is also the (at least equally important) consequence you may be missing that the rule has on opportunities to alias a register variable... Finally, with regard to your comments about the place of optimizing compilers in C: "Smaller, faster programs can be expected if register declarations are used appropriately, but future improvements in code generation may render them unnecessary" [Appendix A, 8.1] Thus anticipating the future obsolesence of "register" as optimizers improve. This is a good point. My answer to it is that Ritchie was too hopeful and that when he foresaw the rise of optimizers he could not anticipate that aggressive optimizers would turn out to be as a rule large, mostly slow, quite often very buggy, and how effective "register" could be in achieving efficient code at far lower expense. Also, he might have missed the important point that an automated optimizer can do reliably only a static analysis of frequency of use of variables, without resorting to really amazing technology and/or information on the expected distribution of input data. If K&R is not a good sign of the original intent of a keyword, what are you using as your authority? A different, but still equally plausible, and maybe better, reading of K&R than yours. And, maybe, some extra contextual information on how and why C was designed and evolved in its early (pre BSD, pre SysV) history. -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
ok@quintus.uucp (Richard A. O'Keefe) (12/19/88)
In article <420@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >In article <860@quintus.UUCP> ok@quintus.UUCP (Richard A. O'Keefe) writes: > [ on my suggestion to make "char int" denote guaranteed signed chars ] > That change would *FORCE* compiler writers to break working code. >Why ever? I have never advocated removing the rule that "char" by itself is >either "int" or "unsigned", merely added a way to guarantee that it would be >signed. So sorry! I thought you wanted your proposal to be self-consistent. Silly me. The proposal, as I understood it, was that 'char' was to be a size modifier _just_ _like_ 'short' and 'long'. Now the rule is that short x; == short int x; long x; == long int x; so naturally I assumed that you were proposing that char x; == char int x; (Certainly "short short" would have worked like that.) > but X3J11 didn't introduce incompatibility lightly. > >Yet it introduced an unnecessary keyword. It has been explained that X3J11 did not "introduce" the 'signed' keyword, but accepted it as _existing_ _practice_. If someone else has tried to deal with a problem, you don't spit in their face even if you don't like their solution much. >Indeed!. Since 'char' is to be a length modifier, I assumed it was obvious >that in case the base type is missing, it would default to either 'int' or >'unsigned', while for all other length modifiers it would always default to >'int'. I'm sorry, but I don't see how such an exception is "obvious". I personally regard the whole of C's integer type system as radically misguided, and would argue with the utmost vehemence against its adoption in any other language. But C is the way it is, and there is no use crying over spilt milk. It's usable, it's understood. Let's freeze it and get on to better things.
guy@auspex.UUCP (Guy Harris) (12/20/88)
> No, that's not what he meant: he meant that your definitions of > "correct" and "incorrect" are historically wrong, > >As somebody else has remarked to you, in the classic era of C, long since >dead, it was *unthinkable* that the compiler would be much more than a clever >translator. Err, umm, I think Henry was around in the classic era of C; so was I, and so, I suspect, was Doug Gwyn. It was never obvious to me that it was "unthinkable", even if compilers at the time may not have done it (although I know the VAX PCC's "c2" optimizer would do optimizations like that - or, at least, the S3-vintage one in 4.xBSD, and I seem to remember somebody, either Doug Gwyn or Henry Spencer, saying that the Ritchie compiler would do so as well). >Register, +=, ++, are all sure signs that C was meant to be compiled by >a simple compiler that relied on the programmer to use such constructs >to help code generation. Err, umm, I seem to remember that "+=" was also present in Algol 68; does that mean that it was also meant to be compiled by "a simple compiler...." > implemented, and used. > >On PCs, on PCs... And UNIX systems. Did you not read the article posted by Doug Gwyn in which he stated Wrong. Even Ritchie's PDP-11 C compiler would occasionally do things when the peephole optimizer was enabled that caused trouble in device drivers, etc. This was not generally considered a bug; one merely revised the code to outwit the optimizer or else turned off the optimizer. Many of these problems could have been circumvented through the use of "volatile", if it had existed. or did you simply choose to pretend he didn't say this?
henry@utzoo.uucp (Henry Spencer) (12/20/88)
In article <422@aber-cs.UUCP> pcg@cs.aber.ac.uk (Piercarlo Grandi) writes: >As somebody else has remarked to you, in the classic era of C, long since >dead, it was *unthinkable* that the compiler would be much more than a clever >translator... Curious, it was never unthinkable for me. In fact, it's never been true, given some of the peephole optimizations that even the original Ritchie compiler was quite happy to do. >After all, the Ritchie PDP-11 compiler was known as the "Standard C Compiler" >for some reason, wasn't it? I never heard it called that, actually, that I recall. I've only been using it since 1975, mind you. >Register, +=, ++, are all sure signs that C was meant to be compiled by a simple >compiler that relied on the programmer to use such constructs to help code >generation. Not really. For one thing, operators like += (originally =+) are a significant convenience even without any code-generation implications. For another, you've missed a crucial distinction: some of these operators make it *possible* for a relatively simple compiler to generate good code, given a clever programmer. That does not imply that this was the only mode of operation contemplated; some of DMR's own comments here and there specifically indicate that he anticipated higher optimization later. >Just a moment. Ritchie never explicitly did allow aggressive optimization. Nor did he disallow it. >... Ritchie introduced >"register" in Classic C, not "volatile", after all, and this *means* >something. If he had meant aggressive optimization to be allowed, he might >not have introduced "register"... You are confusing *allowing* aggressive optimization with *requiring* it. DMR put "register" in so that good code could be generated without major optimization, but it was never meant to preclude more sophisticated means. DMR himself observes in K&R1 that improved optimization might render the "register" keyword unnecessary. >he would have surely deemed "volatile" >absolutely necessary, the more so as he used C to write, of all things, >Unix's device drivers. Dennis didn't set out to solve all the world's problems right from the beginning. If he thought about the issue, he probably assumed that it would be dealt with, by him or someone else, when the problem began to become too serious for simple workarounds. It has been. > implemented, and used. > >On PCs, on PCs... I don't understand this interjection. If you intend to imply that my views have been formed on PCs, this is laughable -- I've never compiled a C program on a PC in my life. (Well, I think I compiled a five-line one on a PC running Coherent once, after I asked Randall Howard whether I could try to crash it and he said "go ahead". Famous last words... :-)) I learned C on a pdp11 with the Ritchie compiler under V5 (later V6 and V7). > Might one ask how long you have been using C, Mr. Grandi? > >Regularly, since 1980 (of course I had already bought K&R as soon as it was >out). Probably my main impulse in extolling the virtues of Classic C is >therefore plain old nostalgia for the good ol' days of V7 Unix and C... What good ol' days? "The thing history teaches us is that there never were any good old days." utzoo was a pdp11 running V7 until about 6 months ago. The 11 is now our terminal server, so we still use the old compiler on occasion for maintaining its software. As I alluded to above, C has been my major programming language since 1975. I'm afraid that I can't get nostalgic over a "Classic C" that never was. -- "God willing, we will return." | Henry Spencer at U of Toronto Zoology -Eugene Cernan, the Moon, 1972 | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/20/88)
>Register, +=, ++, are all sure signs that C was meant to be compiled by >a simple compiler that relied on the programmer to use such constructs >to help code generation. Err, umm, I seem to remember that "+=" was also present in Algol 68; You remember well... does that mean that it was also meant to be compiled by "a simple compiler...." You will also remember as well that they were introduced into the language precisely to offer a cheap opportunity for the compiler to generate good code without too much effort. While Algol68 is a compiler writer's nightmare from a parsing viewpoint (and the support library is not easy to write as well), it was carefully designed not to require complex code generation. The and-becomes operators were one of the neatest ideas, readily borrowed in C. > implemented, and used. > >On PCs, on PCs... And UNIX systems. Did you not read the article posted by Doug Gwyn in which he stated Wrong. Even Ritchie's PDP-11 C compiler would occasionally do things when the peephole optimizer was enabled that caused trouble in device drivers, etc. This was not generally considered a bug; one merely revised the code to outwit the optimizer or else turned off the optimizer. Many of these problems could have been circumvented through the use of "volatile", if it had existed. or did you simply choose to pretend he didn't say this? It so happens that his article has received this site only today, as far as I could see (note that occasionally articles get lost as well). I have already answered him privately, because I'd rather not debate publicly an article so rich in morbid comments (it is me that is using "sleazy ploys"? hey man, watch your ton.. oops keyboard :-) !) and other exercises of style. In any case, I don't see as my duty to address all the funny things certain people say. It will be my pleasure however to address that message as soon as I have time to digest it, because finally it contains some arguments, and they are exactly those I had expected (...leave elegance to tailors :->). As to the matter in the specific paragraph you cite, I thought it was obvious that it supports my arguments. It merely reiterates what is common knowledge, that even PCC peephole optimizers tend to be quite buggy, and in more than one way. What you "generally" consider to be a bug or a feature is your business after all, but word twisting can only go so far. Me, I see this as a further reason to believe that optimizers are often not reliable, and relying on ever more complex ones should not be encouraged, by way of volatile, on purely technical grounds. After all register will work even if you don't use the optimizer, will it? -- Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
guy@auspex.UUCP (Guy Harris) (12/20/88)
>This is a good point. My answer to it is that Ritchie was too hopeful and >that when he foresaw the rise of optimizers he could not anticipate that >aggressive optimizers would turn out to be as a rule large, mostly slow, >quite often very buggy, and how effective "register" could be in achieving >efficient code at far lower expense. Please note that there are those who would - with good reason - claim that there exist agressive optimizers that *are* cost-effective (cf. MIPS). Please note also that aggressive optimizers do more than just choose whether to put variables into registers. Please note, therefore, that your sweeping claim may fail to convince (as is the case with a lot of sweeping claims posted to USENET; why do those who present sweeping claims merely repeat them more loudly when they are disputed? Do they think that their mere *insistence* of the validity of those claims will convince people to dispute facts that oppose those claims?). >A different, but still equally plausible, ...but neither more nor less plausible... >and maybe better, ...and maybe worse... >reading of K&R than yours. In other words, it is at best a debate between two people reading the same stuff different ways, although one side (the minority one, apparently) is reading a lot more into the statements in K&R than the other. Frankly, unless and until DMR himself states that your interpretation is correct, I'm going to assume that the less aggressive, if you will, interpetation (i.e., the one that reads less into it) is correct. >And, maybe, some extra contextual information on how and why C >was designed Oh, so you were there when it was designed, or perhaps personally involved in its design? >and evolved in its early (pre BSD, pre SysV) history. *Sigh* as has been stated before, the Ritchie compiler (pre-3BSD, pre-System V) performed what you might well consider "aggressive" optimizations, as Doug Gwyn states.
pcg@aber-cs.UUCP (Piercarlo Grandi) (12/20/88)
In article <753@auspex.UUCP> guy@auspex.UUCP (Guy Harris) writes:
# Oh wow, another *ex cathedra* pronouncement from Pontifex Grandi I.
The only one that takes tremendously seriously his own postings is you, Guy.
It is you that is getting in the popist mould, scorching the heretic with
excommunications. I may be advocating unfashionable ideas, but with
reasonable arguments, and ones that people can understand, and can debate and
so gain more understanding of the issues, if they want.
I am merely trying to persuade you that there are good points to be made on
my side as well, not that I am infallible like a committee :->. All I get in
return is cheap jabs at my person.
# Please note that there are those who would - with good reason - claim
# that there exist agressive optimizers that *are* cost-effective (cf.
# MIPS).
Oh yes. But the existence of people that claim, with fair and reasonable
arguments, that aggressive optimization works so well on their hardware (and
can be ported to other architectures as well), does not imply that it is a
generally desirable idea. C and UNIX were designed by and for the people that
could not afford the MIPSes of their day, weren't they? Cost effectiveness
depends a lot on what you happen to have in your wallett... Is by any chance
your example meant to show that dpANS C is custom designed for well heeled
customers of the MIPSes of this world :-( ? :-> :->.
# Please note also that aggressive optimizers do more than just choose
# whether to put variables into registers.
Indeed, indeed. Please note that I have never said otherwise (I am even on
record as having admitted that they do also introduce many interesting
bugs). While I think that register variable selection is one of the
optimizations that are best left to the programmer, if he is competent
enough, I have given some examples of optimizations that I think best not to
leave to the programmer. Please note that the sad argument about complex
optimizer (un)reliability stands high in many people's everyday experience.
--
Piercarlo "Peter" Grandi INET: pcg@cs.aber.ac.uk
Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg
UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
chip@ateng.ateng.com (Chip Salzenberg) (12/22/88)
According to pcg@aber-cs.UUCP (Piercarlo Grandi), concerning the fact that the signedness of char is implementation-defined: >[...] it is apparent in hindsight that syntax and >semantics are incomplete, as there is no way to ensure the signedness of a >"char" (a similar problem exists with bit fields), and that syntax does not >properly reflect semantics. Sure. But for hysterical -- oops, I meant historical -- reasons, X3J11 couldn't fix it. They did provide a way to specify signed and unsigned chars when we care to, which is all we really need anyway. >My contentions (for the last time!) are that > [1] this is not necessary, as it is more natural to drop the pretense > that "char" is a type distinct from "int", and instead adopt the notion > that "char" is like "short", an adjective that modifies the length of its > base type; Well, sure. But you're too late. X3J11 did a good job. Let's leave well enough alone. -- Chip Salzenberg <chip@ateng.com> or <uunet!ateng!chip> A T Engineering Me? Speak for my company? Surely you jest! Beware of programmers carrying screwdrivers.
guy@auspex.UUCP (Guy Harris) (12/22/88)
>As to the matter in the specific paragraph you cite, I thought it was obvious >that it supports my arguments. It's "obvious" only if you take "optimizing references to variables in C is bad" as an axiom. You seem to take it as an axiom. Others do not. >It merely reiterates what is common knowledge, that even PCC peephole >optimizers tend to be quite buggy, 1) Ritchie's compiler wasn't PCC-based 2) it only reiterates that if you consider optimizing references to variables in that fashion to be a bug. Again, others do not. Note that in the cases where you consider X to be true, and others do not, it should be quite apparent that repeating "X is true" 5000 times is only going to annoy the others, not convince them. >What you "generally" consider to be a bug or a feature is your >business after all, but word twisting can only go so far. Just because *you* consider it to be a bug, does that make it a bug even if 99% of the users of the Ritchie compiler did not? Yeesh. Talk about word-twisting; the pretzel factory seems to be working overtime....
guy@auspex.UUCP (Guy Harris) (12/22/88)
>The only one that takes tremendously seriously his own postings is you, >Guy. Rubbish. Anybody who REFUSES to believe that optimizing repeated references to variables, say, is anything other than a bug, and who REFUSES to believe that aggressive optimization can be beneficial, and REFUSES to give any evidence other than repeated postings of his own pure opinions, is taking himself far more seriously than he deserves. That description fits you to a T, as *several* of the other posters on this topic will agree. >It is you that is getting in the popist mould, scorching the heretic with >excommunications. I may be advocating unfashionable ideas, but with >reasonable arguments, Excuse me, but who died and left you in charge, so that merely by *stating* that your arguments are reasonable you can render them reasonable? Frankly, several people whose opinion I *highly* respect, based on *demonstrated* technical competence, disagree with your arguments and seem to disagree that they are reasonable. >I am merely trying to persuade you that there are good points to be made on >my side as well, not that I am infallible like a committee :->. All I get in >return is cheap jabs at my person. Right. I'm sorry, but I can only conclude that somebody who REFUSES to believe that those arguing with him can possibly be correct, and REPEATEDLY claims that in some so-called "Classic" era of C it was considered "unthinkable" to do the aforementioned types of optimization and REFUSES to provide ANY objective evidence for this (and apparently makes up reasons to dismiss evidence to the contrary) sure sounds like he considers himself infallible. >Oh yes. But the existence of people that claim, with fair and reasonable >arguments, that aggressive optimization works so well on their hardware (and >can be ported to other architectures as well), does not imply that it is a >generally desirable idea. *What*? I very much doubt that the MIPS people don't think that aggressive optimization is a generally-desirable idea. In fact, I have obtained the impression that they *did* think so - if they didn't, why would they have bothered? >C and UNIX were designed by and for the people that could not afford >the MIPSes of their day, weren't they? Define "MIPSes of their day". MIPS boxes are hardly megabuck mainframes. They are actually quite cost-effective. >Indeed, indeed. Please note that I have never said otherwise (I am even on >record as having admitted that they do also introduce many interesting >bugs). While I think that register variable selection is one of the >optimizations that are best left to the programmer, if he is competent >enough, I have given some examples of optimizations that I think best not to >leave to the programmer. Please note that the sad argument about complex >optimizer (un)reliability stands high in many people's everyday experience. I hardly think there is a consensus for your view that aggressive optimization of C is a Bad Thing. Heck, a simple-minded assembler can quite likely be more bug-free than most non-aggressively-optimizing C compilers; shall we then discard C? One can reasonably discuss the question of whether aggressive optimization is a Good Thing. One cannot do so, however, if one of those involved in the discussion offers arguments that reduce to "obviously, it's bad" rather than citing *objective* data to indicate that it might be bad. A lot of the hostility towards your postings is really hostility towards your totally-unjustified unshakable faith in your beliefs; when people *repeatedly* cite objective reasons *why* your believes are *not* correct, you either ignore them or come up with even more pronouncements (i.e., in response to people pointing out that "Classic" C compilers did - *deliberately* - perform the optimizations you decry, you simply dismiss that as being an indication that the compilers in question are "buggy").