martin@mwtech.UUCP (Martin Weitzel) (05/23/91)
There has recently been some discussion about the correct way to write comparison functions for qsort. (I've seen it as well in the CUJ as also in a local German group). There seems to be some consensus that the comparison function must be written expecting two pointers to void and eventually casting (or assigning) them internally to the required pointer type. Taking into consideration that the number and types of function parameters for any function determines the calling sequence and further considering that qsort already makes a call to the comparison function (via the function pointer) and hence has a certain calling sequence compiled in, this all seems reasonable to me. (By "calling sequence" I mean the details how parameters are transferred to the function from the place where the function is called and how the parameters are accessed from inside the function. Of course, both ways must match.) But have a look at the example in K&R-II, page 119-120 and the explanations that accompany it - isn't it, say, at least a bit misleading, or, may be, even wrong? (Oh boy, was this hard to type in now, suspecting the fathers of C to have written something that might be wrong.) The point in question is the cast of the comparison function pointer when handed as parameter to qsort and the explanation for the cast: "The elaborate cast of the function argument casts the arguments of the comparison function. These will generally have no effect on actual representation but assure the compiler that all is well." First, IMHO the cast they apply has not the least effect on the ARGUMENTS of the COMPARISION function; Second, IMHO ANSI C even GUARANTEES that the cast has no effect on the REPRESENTATION, since all function pointers have the same representation and pointers to char have the same representation as pointers to void. (This second point would really be of minor importance - basically it centers on whether one could omit "generally" from the last sentence above. As this sentence could be seen to refer also to the sentence immediately before the one with which I started my citation, one could even argue that the "generally" justified. But I mention it because I think it points the naive reader into quite a wrong direction.) Third and most important: Will the guarantees ANSI C gives with respect to the (identical) representation of certain pointer types extend to the calling sequence of a function? Or, in the context of the above example: Does the identical representation of pointers to char and pointers to void extend to an identical calling sequence for |int f1(void *, void *)| and |int f2(char *, char *)| ? If not, the example in K&R-II is not guaranteed to work! -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83
gwyn@smoke.brl.mil (Doug Gwyn) (05/24/91)
In article <1145@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes: > "The elaborate cast of the function argument casts the > arguments of the comparison function. These will generally > have no effect on actual representation but assure the > compiler that all is well." K&R2 was written before the final ANSI C standard was published. In fact, at the time it was written it was technically wrong on this point. However, since then X3J11 decided to require void* and char* to have the same representation, and via a "trickle-up" effect this implies compatiblility of the two types of function- pointer argument to qsort(). However, I recommend coding the function according to the correct interface specification and using casts within the function to adapt it to the actual situation.
diamond@jit533.swstokyo.dec.com (Norman Diamond) (05/24/91)
In article <1145@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes: >There has recently been some discussion about the correct way to >write comparison functions for qsort. There seems to be some >consensus that the comparison function must be written expecting >two pointers to void and eventually casting (or assigning) them >internally to the required pointer type. I'd agree with that. >But have a look at the example in K&R-II, page 119-120 Sorry, I don't have one, but ... >(Oh boy, was this hard to type in now, suspecting the fathers of C to >have written something that might be wrong.) There are a few errors and inconsistencies in K&R-I. And actually I'm waiting for K&R-III, because the proposed standard changed a little bit after K&R-II and before finalization. > "The elaborate cast of the function argument casts the > arguments of the comparison function. These will generally > have no effect on actual representation but assure the > compiler that all is well." This wording appears very sloppy, and as you said, gives wrong impressions. It's not clear if the authors made a technical error (which is entirely possible) in addition to sloppy wording. (Their code might make it clear.) >Third and most important: Will the guarantees ANSI C gives with >respect to the (identical) representation of certain pointer types >extend to the calling sequence of a function? No. A function with two parameters might have a different calling sequence from a function with zero parameters. A function with an int parameter might have a different calling sequence from a function with a struct parameter. >Does the identical representation of pointers to char and pointers to void >extend to an identical calling sequence for > int f1(void *, void *) and int f2(char *, char *) ? I think yes. The two function types are not compatible (by the definition of compatible) but should be interchangeable (no definition here) because of the identical representation of void* and char*. -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it. Permission is granted to feel this signature, but not to look at it.
diamond@jit533.swstokyo.dec.com (Norman Diamond) (05/24/91)
To clarify my article <1991May24.005025.7714@tkou02.enet.dec.com>: >In article <1145@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes: >>Third and most important: Will the guarantees ANSI C gives with >>respect to the (identical) representation of certain pointer types >>extend to the calling sequence of a function? > >No. A function with two parameters might have a different calling sequence >from a function with zero parameters. A function with an int parameter might >have a different calling sequence from a function with a struct parameter. The identical representation of void* and char* includes their appearance in calling sequences of functions. If that is what you meant, then the answer is yes. But two pointers to arbitrary function types, while they must have identical representations, do not have identical calling sequences. Sorry about overlooking your probably intended meaning. -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it. Permission is granted to feel this signature, but not to look at it.
gwyn@smoke.brl.mil (Doug Gwyn) (05/25/91)
In article <1991May24.005025.7714@tkou02.enet.dec.com> diamond@jit533.enet@tkou02.enet.dec.com (Norman Diamond) writes: >There are a few errors and inconsistencies in K&R-I. And actually I'm waiting >for K&R-III, because the proposed standard changed a little bit after K&R-II >and before finalization. I'm not aware of any changes between the final draft of K&R2 (first printing) and the official C standard that would make K&R2 less correct; however, there was at least one change that made K&R2 more nearly correct.
henry@zoo.toronto.edu (Henry Spencer) (05/26/91)
In article <16259@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >I'm not aware of any changes between the final draft of K&R2 (first printing) >and the official C standard that would make K&R2 less correct... I know of at least one -- it's no longer promised that casting a pointer to integer and back preserves its value if the integer is big enough -- and there are probably a few more. -- "We're thinking about upgrading from | Henry Spencer @ U of Toronto Zoology SunOS 4.1.1 to SunOS 3.5." | henry@zoo.toronto.edu utzoo!henry
diamond@jit533.swstokyo.dec.com (Norman Diamond) (05/27/91)
In article <16259@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >In article <1991May24.005025.7714@tkou02.enet.dec.com> diamond@jit533.enet@tkou02.enet.dec.com (Norman Diamond) writes: >>There are a few errors and inconsistencies in K&R-I. And actually I'm waiting >>for K&R-III, because the proposed standard changed a little bit after K&R-II >>and before finalization. > >I'm not aware of any changes between the final draft of K&R2 (first printing) >and the official C standard that would make K&R2 less correct; however, there >was at least one change that made K&R2 more nearly correct. dmr posted a list of changes about two years ago. I'm not sure if I have it in the portion of a damaged tape that might be recoverable. (Warning about backups: when you make tapes on two different machines, in case one machine might be misaligned or otherwise make tapes that no one else can read ... well, dual redundancy might not be enough.) -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it. Permission is granted to feel this signature, but not to look at it.
gwyn@smoke.brl.mil (Doug Gwyn) (05/27/91)
In article <1991May25.221756.16182@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <16259@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >>I'm not aware of any changes between the final draft of K&R2 (first printing) >>and the official C standard that would make K&R2 less correct... >I know of at least one -- it's no longer promised that casting a pointer to >integer and back preserves its value if the integer is big enough -- and >there are probably a few more. X3.159-1989 Section 3.3.4 Semantics require that there be some such implementation-defined type. Well, actually, it doesn't require that the "before" and "after" pointers compare equal, but that is clearly the intent, for implementations where this is even possible. There can be some implementations with, say, 128-bit addresses and 64-bit data words, for which some information would necessarily be lost by the transformation. Thus, while K&R2 section A6.6 technically promises more than the C standard requires, it does indicate what the intended behavior is, for implementations for which it is feasible. Was that really changed during the public review process? I don't have the old drafts to look it up in.
gwyn@smoke.brl.mil (Doug Gwyn) (05/27/91)
In article <1991May27.003536.25876@tkou02.enet.dec.com> diamond@jit533.enet@tkou02.enet.dec.com (Norman Diamond) writes: >In article <16259@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >>I'm not aware of any changes between the final draft of K&R2 (first printing) >>and the official C standard that would make K&R2 less correct; however, there >>was at least one change that made K&R2 more nearly correct. >dmr posted a list of changes about two years ago. While that's true, it doesn't invalidate what I said. The only substantive change of any note in the errata list that could be blamed on late changes in the draft standard was CLK_TCK => CLOCKS_PER_SEC.
diamond@jit533.swstokyo.dec.com (Norman Diamond) (05/27/91)
In article <16271@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >In article <1991May25.221756.16182@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >>In article <16259@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >>>I'm not aware of any changes between the final draft of K&R2 (first printing) >>>and the official C standard that would make K&R2 less correct... >>I know of at least one -- it's no longer promised that casting a pointer to >>integer and back preserves its value if the integer is big enough -- and >>there are probably a few more. > >X3.159-1989 Section 3.3.4 Semantics require that there be some such >implementation-defined type. Well, actually, it doesn't require that >the "before" and "after" pointers compare equal, but that is clearly >the intent, for implementations where this is even possible. I nearly pounced on the first sentence with a "wrong" (in the style that Mr. Gwyn was famous for, though recently he seems more sociable). The second sentence indeed points out that the first one is wrong. As for intents, Section 3.3.4, and even the footnote, do not say. There is no requirement and not even a suggestion. Intuitively, and for quality of implementation, one might like to see it. However, neither portable code nor strictly conforming code could make any use of it. -- Norman Diamond diamond@tkov50.enet.dec.com If this were the company's opinion, I wouldn't be allowed to post it. Permission is granted to feel this signature, but not to look at it.
henry@zoo.toronto.edu (Henry Spencer) (05/27/91)
In article <16271@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >>I know of at least one -- it's no longer promised that casting a pointer to >>integer and back preserves its value if the integer is big enough... > >...Was that really changed during the public review process? I don't >have the old drafts to look it up in. I don't have them handy either. I remember noticing that the "you can do this" promise had disappeared, but I have no idea when it was. Probably something to do with the AS/400. :-) -- "We're thinking about upgrading from | Henry Spencer @ U of Toronto Zoology SunOS 4.1.1 to SunOS 3.5." | henry@zoo.toronto.edu utzoo!henry
david@sco.COM (David Fiander) (05/28/91)
In article <1991May27.153520.4547@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <16271@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >>>I know of at least one -- it's no longer promised that casting a pointer to >>>integer and back preserves its value if the integer is big enough... >> > >I don't have them handy either. I remember noticing that the "you can do >this" promise had disappeared, but I have no idea when it was. > >Probably something to do with the AS/400. :-) From what you've (or was it doug) said, that wouldn't surprise me, but the same thing happens on the CDC Cyber series, and probably on the Prime 9600 series (I can't check, it's not up right now). These machines use rings for protection and, on the Cybers, converting from a pointer to an int may be all right, but converting from an int to a pointer zeros the ring bits in the pointer created. This caused us all sorts of problems, because the test p == (char *)-1 will have a different result from the test (int)p == -1 malloc broke because of this, and it took us two or three 12-hour days to figure it out. -- David J. Fiander SCO MMDF Development Team SCO Canada, Inc.
norvell@csri.toronto.edu (Theo Norvell) (05/29/91)
In article <1991May28.124930.19893@sco.COM> david@sco.COM (David Fiander) writes: >>In article <16271@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes: >>>>I know of at least one -- it's no longer promised that casting a pointer to >>>>integer and back preserves its value if the integer is big enough... >>> >on the Cybers, > > p == (char *)-1 > >will have a different result from the test > > (int)p == -1 > It would be a bit much to expect there to be a bijection between 48 bit pointers and 64 bit integers. On recent 180 C compilers p == (char *)(int)p which is what Doug was talking about. The value is preserved, even if the representation is not. This is because pointer comparison ignores ring numbers -- it has to or two pointers to the same object could compare as different.