On 06/22/2017 06:20 PM, DFS wrote:
> On 6/22/2017 5:55 PM, James R. Kuyper wrote:
>> On 06/22/2017 04:09 PM, DFS wrote:
>>>
>>> int compare (const void * a, const void * b)
>>> {return strcmp((const char *)a, (const char *)b);}
>>
>> The casts are unnecessary - the exact same conversions will occur
>> implicitly if you leave them out, so long as there's a function
>> prototype for strcmp() in scope.
>
>
> All the examples I found online were like that.
You'll find a lot of bad code online. It is, in general, a lot easier to
find than good code.
> This worked without a strcasecmp prototype:
>
> int comparechar (const void * a, const void * b)
> {return strcasecmp(a,b);}
>
>
> TinyC compiler Windows
In C90, if an unrecognized identifier was used in a context where a
function call was allowed, the identifier was assumed to be a function
returning 'int'. The default argument promotions (6.5.2.2p6) were
performed on the arguments, and it was simply assumed that the result of
those promotions was compatible with the types of the parameters in the
actual function definition. If both of those assumptions turned out to
be correct, such code had well-defined behavior. Otherwise, the behavior
was undefined. This is part of the feature called "implicit int".
I first learned C in 1979, and my teacher was already telling us that
relying on implicit int was a bad idea; I never did so deliberately. It
was removed in C99 - code like that is now a constraint violation. Which
is one of the reasons why you should compile your code using command
line options putting your compiler into C99 mode, if it has any.
The successful execution of your code also relies upon the fact that
char* and void* have exactly the same representation and alignment
requirements (6.2.5p28). Footnote 48 says: "The same representation and
alignment requirements are meant to imply interchangeability as
arguments to functions, return values from functions, and members of
unions.". In practice, that usually works out, as it did in your case.
However, footnotes are not normative text, and it's entirely possible
for an implementation to meet 6.2.5p28's requirements without making
them interchangeable. For example, the platform's calling conventions
could specify that void* arguments are passed in even-numbered
registers, while char* arguments are passed in odd-numbered registers. I
point this out, not because it's likely - there's no good reason I can
think of why any implementation would do anything like that. I point it
out because the standard permits it, and I would prefer the standard be
changed to mandate the interchangeability it mentions in footnote 48. It
also mentions interchangeability in footnotes 41 and 258, and I would
like to see interchangeability be mandated in those cases as well.