Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #61598 > unrolled thread
| Started by | David Brown <david.brown@hesbynett.no> |
|---|---|
| First post | 2015-05-06 10:02 +0200 |
| Last post | 2015-05-07 10:11 +0100 |
| Articles | 18 on this page of 38 — 13 participants |
Back to article view | Back to comp.lang.c
Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-06 10:02 +0200
Re: Return value for strcat and similar functions Xavier Roche <xroche@free.fr.NOSPAM.invalid> - 2015-05-06 10:34 +0200
Re: Return value for strcat and similar functions Lőrinczy Zsigmond <zsiga@nospam.for.me> - 2015-05-06 16:51 +0200
Re: Return value for strcat and similar functions Keith Thompson <kst-u@mib.org> - 2015-05-06 08:58 -0700
Re: Return value for strcat and similar functions Richard Heathfield <rjh@cpax.org.uk> - 2015-05-06 17:07 +0100
Re: Return value for strcat and similar functions Morris Dovey <mrdovey@iedu.com> - 2015-05-06 12:01 -0500
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-07 10:19 +0200
Re: Return value for strcat and similar functions glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-05-07 13:21 +0000
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-07 16:24 +0200
Re: Return value for strcat and similar functions glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-05-07 18:02 +0000
Re: Return value for strcat and similar functions Morris Dovey <mrdovey@iedu.com> - 2015-05-07 10:17 -0500
Re: Return value for strcat and similar functions Morris Dovey <mrdovey@iedu.com> - 2015-05-07 10:56 -0500
Re: Return value for strcat and similar functions asetofsymbols@gmail.com - 2015-05-07 11:00 -0700
Re: Return value for strcat and similar functions Morris Dovey <mrdovey@iedu.com> - 2015-05-07 14:28 -0500
Re: Return value for strcat and similar functions asetofsymbols@gmail.com - 2015-05-07 12:47 -0700
Re: Return value for strcat and similar functions Nathan Wagner <nw@hydaspes.if.org> - 2015-05-08 09:31 +0000
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-07 15:55 -0700
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-08 11:03 +0200
Re: Return value for strcat and similar functions Morris Dovey <mrdovey@iedu.com> - 2015-05-08 05:07 -0500
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-06 18:25 -0700
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-07 10:22 +0200
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-07 15:39 -0700
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-08 11:09 +0200
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-10 08:44 -0700
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-10 21:30 +0200
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-11 20:42 -0700
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-12 09:52 +0200
Re: Return value for strcat and similar functions Bartc <bc@freeuk.com> - 2015-05-12 13:33 +0100
Re: Return value for strcat and similar functions Ike Naar <ike@iceland.freeshell.org> - 2015-05-14 20:15 +0000
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-14 23:06 +0200
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-20 11:08 -0700
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-21 10:55 +0200
Re: Return value for strcat and similar functions glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-05-21 13:05 +0000
Re: Return value for strcat and similar functions David Brown <david.brown@hesbynett.no> - 2015-05-21 20:42 +0200
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-07-10 10:40 -0700
Re: Return value for strcat and similar functions raltbos@xs4all.nl (Richard Bos) - 2015-05-08 21:56 +0000
Re: Return value for strcat and similar functions Tim Rentsch <txr@alumni.caltech.edu> - 2015-05-10 09:07 -0700
Re: Return value for strcat and similar functions Bartc <bc@freeuk.com> - 2015-05-07 10:11 +0100
Page 2 of 2 — ← Prev page 1 [2]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-07 10:22 +0200 |
| Message-ID | <mif7an$hem$1@dont-email.me> |
| In reply to | #61654 |
On 07/05/15 03:25, Tim Rentsch wrote: > David Brown <david.brown@hesbynett.no> writes: > >> Does anyone know why the return value for strcat and similar library >> functions is defined in such an unhelpful (IMHO) way? >> >> The return value of strcat(s1, s2) is always s1, which is a value you >> already have available. Returning a pointer to the end of s1 (i.e., s1 >> + strlen(s1)) would be much more efficient when building up a string >> from parts. > > You're assuming that the value of the first argument is readily > available otherwise, which isn't always true - it could be the > result of a function call, for example. > It /is/ readily available - if you as a programmer need it, you have access to it. If your "s1" is the result of calling "foo()", then all you need to write is "strcat(s1 = foo(), s2)".
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-05-07 15:39 -0700 |
| Message-ID | <kfny4l0f1wi.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #61673 |
David Brown <david.brown@hesbynett.no> writes: > On 07/05/15 03:25, Tim Rentsch wrote: >> David Brown <david.brown@hesbynett.no> writes: >> >>> Does anyone know why the return value for strcat and similar library >>> functions is defined in such an unhelpful (IMHO) way? >>> >>> The return value of strcat(s1, s2) is always s1, which is a value you >>> already have available. Returning a pointer to the end of s1 (i.e., s1 >>> + strlen(s1)) would be much more efficient when building up a string >>> from parts. >> >> You're assuming that the value of the first argument is readily >> available otherwise, which isn't always true - it could be the >> result of a function call, for example. > > It /is/ readily available - Not exactly. What you mean is not that it is readily available but that it can be made available, by declaring a variable and assigning the returned value. > if you as a programmer need it, you have > access to it. If your "s1" is the result of calling "foo()", then all > you need to write is "strcat(s1 = foo(), s2)". My point is either choice has its own advantages. Personally I think the choice made for strcat() is the right one for what it is. If something different or more elaborate is wanted, it's easy enough to program that.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-08 11:09 +0200 |
| Message-ID | <mihue7$t9s$1@dont-email.me> |
| In reply to | #61732 |
On 08/05/15 00:39, Tim Rentsch wrote: > David Brown <david.brown@hesbynett.no> writes: > >> On 07/05/15 03:25, Tim Rentsch wrote: >>> David Brown <david.brown@hesbynett.no> writes: >>> >>>> Does anyone know why the return value for strcat and similar library >>>> functions is defined in such an unhelpful (IMHO) way? >>>> >>>> The return value of strcat(s1, s2) is always s1, which is a value you >>>> already have available. Returning a pointer to the end of s1 (i.e., s1 >>>> + strlen(s1)) would be much more efficient when building up a string >>>> from parts. >>> >>> You're assuming that the value of the first argument is readily >>> available otherwise, which isn't always true - it could be the >>> result of a function call, for example. >> >> It /is/ readily available - > > Not exactly. What you mean is not that it is readily available > but that it can be made available, by declaring a variable and > assigning the returned value. That is certainly what /I/ mean be "readily available". You can get the value by simply attaching a name to it - that's good enough. > >> if you as a programmer need it, you have >> access to it. If your "s1" is the result of calling "foo()", then all >> you need to write is "strcat(s1 = foo(), s2)". > > My point is either choice has its own advantages. Personally I think > the choice made for strcat() is the right one for what it is. If > something different or more elaborate is wanted, it's easy enough > to program that. > I agree that it's easy to write a replacement for strcat() that returns a pointer to the end terminator (or the length of the string, if preferred). And of course your personal opinion is up to you. But I can't see any good reason why the standard library version is specified the way it is, rather than the much more useful alternative of returning a pointer to the end of the string. (And if you want a version returning the first argument, that's easy to write yourself.)
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-05-10 08:44 -0700 |
| Message-ID | <kfn4mnkfne5.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #61755 |
David Brown <david.brown@hesbynett.no> writes: > On 08/05/15 00:39, Tim Rentsch wrote: >> David Brown <david.brown@hesbynett.no> writes: >> >>> On 07/05/15 03:25, Tim Rentsch wrote: >>>> David Brown <david.brown@hesbynett.no> writes: >>>> >>>>> Does anyone know why the return value for strcat and similar >>>>> library functions is defined in such an unhelpful (IMHO) way? >>>>> >>>>> The return value of strcat(s1, s2) is always s1, which is a >>>>> value you already have available. Returning a pointer to the >>>>> end of s1 (i.e., s1 + strlen(s1)) would be much more efficient >>>>> when building up a string from parts. >>>> >>>> You're assuming that the value of the first argument is readily >>>> available otherwise, which isn't always true - it could be the >>>> result of a function call, for example. >>> >>> It /is/ readily available - >> >> Not exactly. What you mean is not that it is readily available >> but that it can be made available, by declaring a variable and >> assigning the returned value. > > That is certainly what /I/ mean be "readily available". You can > get the value by simply attaching a name to it - that's good > enough. I don't want to get into a quibbling match about definitions; the key thing is your description is wrong. You cannot simply attach a name to the needed value - sometimes a name must be declared before being assigned to. That is a non-negligible cost. >>> if you as a programmer need it, you have access to it. If your >>> "s1" is the result of calling "foo()", then all you need to write >>> is "strcat(s1 = foo(), s2)". >> >> My point is either choice has its own advantages. Personally I >> think the choice made for strcat() is the right one for what it >> is. If something different or more elaborate is wanted, it's >> easy enough to program that. > > I agree that it's easy to write a replacement for strcat() that > returns a pointer to the end terminator (or the length of the > string, if preferred). And of course your personal opinion is up > to you. But I can't see any good reason why the standard library > version is specified the way it is, rather than the much more > useful alternative of returning a pointer to the end of the > string. What's wrong with the idea that someone thought it valuable to make the resulting (entire) string available so it could be given, eg, as an argument to another function (or perhaps one branch of a ?: operator, or return expression, etc), taking advantage of a functional style? Is it so hard for you to imagine that someone else would have different priorities than you do? > (And if you want a version returning the first argument, > that's easy to write yourself.) I don't have to, I can just use strcat(). :)
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-10 21:30 +0200 |
| Message-ID | <miobiq$f2o$1@dont-email.me> |
| In reply to | #61820 |
On 10/05/15 17:44, Tim Rentsch wrote: > David Brown <david.brown@hesbynett.no> writes: > >> On 08/05/15 00:39, Tim Rentsch wrote: >>> David Brown <david.brown@hesbynett.no> writes: >>> >>>> On 07/05/15 03:25, Tim Rentsch wrote: >>>>> David Brown <david.brown@hesbynett.no> writes: >>>>> >>>>>> Does anyone know why the return value for strcat and similar >>>>>> library functions is defined in such an unhelpful (IMHO) way? >>>>>> >>>>>> The return value of strcat(s1, s2) is always s1, which is a >>>>>> value you already have available. Returning a pointer to the >>>>>> end of s1 (i.e., s1 + strlen(s1)) would be much more efficient >>>>>> when building up a string from parts. >>>>> >>>>> You're assuming that the value of the first argument is readily >>>>> available otherwise, which isn't always true - it could be the >>>>> result of a function call, for example. >>>> >>>> It /is/ readily available - >>> >>> Not exactly. What you mean is not that it is readily available >>> but that it can be made available, by declaring a variable and >>> assigning the returned value. >> >> That is certainly what /I/ mean be "readily available". You can >> get the value by simply attaching a name to it - that's good >> enough. > > I don't want to get into a quibbling match about definitions; > the key thing is your description is wrong. You cannot simply > attach a name to the needed value - sometimes a name must be > declared before being assigned to. That is a non-negligible > cost. If you think that this cost is non-negligible (assuming a half-decent compiler), then I suppose that explains your problem here. I, on the other hand, have no doubts that it is negligible, and have great difficulty in imagining a situation where it is significantly easier, clearer, faster, or more efficient to use "s1 = strcat(foo(), s2)" rather than "strcat(s1 = foo(), s2)", or my own preferred choice of two lines "s1 = foo(); strcat(s1, s2);". I think that means we have approximately the same definition of "readily available", but different ideas about the cost of attaching a name to a value that the compiler has already calculated and will need later on. > >>>> if you as a programmer need it, you have access to it. If your >>>> "s1" is the result of calling "foo()", then all you need to write >>>> is "strcat(s1 = foo(), s2)". >>> >>> My point is either choice has its own advantages. Personally I >>> think the choice made for strcat() is the right one for what it >>> is. If something different or more elaborate is wanted, it's >>> easy enough to program that. >> >> I agree that it's easy to write a replacement for strcat() that >> returns a pointer to the end terminator (or the length of the >> string, if preferred). And of course your personal opinion is up >> to you. But I can't see any good reason why the standard library >> version is specified the way it is, rather than the much more >> useful alternative of returning a pointer to the end of the >> string. > > What's wrong with the idea that someone thought it valuable to > make the resulting (entire) string available so it could be > given, eg, as an argument to another function (or perhaps one > branch of a ?: operator, or return expression, etc), taking > advantage of a functional style? Is it so hard for you to > imagine that someone else would have different priorities than > you do? The point of this thread was to ask people with different experiences and styles if they could think of an advantage of the way strcat is defined - precisely because while I could not think of one myself, I thought that someone else might. So far no one (including you) has given any suggestions other than "it seemed a good idea at the time" or "they standardised the function they were using, without thinking about other use-cases". This is, of course, entirely normal - most projects of any size have decisions that are odd, inefficient, or unfortunately when looked at later with hindsight. I merely wondered if the early C authors had a good reason that I didn't know of, and it seems not to be the case. > >> (And if you want a version returning the first argument, >> that's easy to write yourself.) > > I don't have to, I can just use strcat(). :) >
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-05-11 20:42 -0700 |
| Message-ID | <kfnpp66cvh0.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #61837 |
David Brown <david.brown@hesbynett.no> writes: > On 10/05/15 17:44, Tim Rentsch wrote: >> David Brown <david.brown@hesbynett.no> writes: >> >>> On 08/05/15 00:39, Tim Rentsch wrote: >>>> David Brown <david.brown@hesbynett.no> writes: >>>> >>>>> On 07/05/15 03:25, Tim Rentsch wrote: >>>>>> David Brown <david.brown@hesbynett.no> writes: >>>>>> >>>>>>> Does anyone know why the return value for strcat and similar >>>>>>> library functions is defined in such an unhelpful (IMHO) way? >>>>>>> >>>>>>> The return value of strcat(s1, s2) is always s1, which is a >>>>>>> value you already have available. Returning a pointer to the >>>>>>> end of s1 (i.e., s1 + strlen(s1)) would be much more efficient >>>>>>> when building up a string from parts. >>>>>> >>>>>> You're assuming that the value of the first argument is readily >>>>>> available otherwise, which isn't always true - it could be the >>>>>> result of a function call, for example. >>>>> >>>>> It /is/ readily available - >>>> >>>> Not exactly. What you mean is not that it is readily available >>>> but that it can be made available, by declaring a variable and >>>> assigning the returned value. >>> >>> That is certainly what /I/ mean be "readily available". You can >>> get the value by simply attaching a name to it - that's good >>> enough. >> >> I don't want to get into a quibbling match about definitions; >> the key thing is your description is wrong. You cannot simply >> attach a name to the needed value - sometimes a name must be >> declared before being assigned to. That is a non-negligible >> cost. > > If you think that this cost is non-negligible (assuming a > half-decent compiler), then I suppose that explains your problem > here. [snip] The cost I'm talking about is a coding and maintenance cost, not a compilation or performance cost. I don't mind agreeing to the possibility that your sense of the size of that cost may be different from mine. >>>>> if you as a programmer need it, you have access to it. If your >>>>> "s1" is the result of calling "foo()", then all you need to write >>>>> is "strcat(s1 = foo(), s2)". >>>> >>>> My point is either choice has its own advantages. Personally I >>>> think the choice made for strcat() is the right one for what it >>>> is. If something different or more elaborate is wanted, it's >>>> easy enough to program that. >>> >>> I agree that it's easy to write a replacement for strcat() that >>> returns a pointer to the end terminator (or the length of the >>> string, if preferred). And of course your personal opinion is up >>> to you. But I can't see any good reason why the standard library >>> version is specified the way it is, rather than the much more >>> useful alternative of returning a pointer to the end of the >>> string. >> >> What's wrong with the idea that someone thought it valuable to >> make the resulting (entire) string available so it could be >> given, eg, as an argument to another function (or perhaps one >> branch of a ?: operator, or return expression, etc), taking >> advantage of a functional style? Is it so hard for you to >> imagine that someone else would have different priorities than >> you do? > > The point of this thread was to ask people with different > experiences and styles if they could think of an advantage of the > way strcat is defined - precisely because while I could not think > of one myself, I thought that someone else might. So far no one > (including you) has given any suggestions other than "it seemed a > good idea at the time" or "they standardised the function they > were using, without thinking about other use-cases". [snip] My answer may not have been stated very clearly, but I did suggest another possible explanation, namely, for reasons you don't consider important, namely coding convenience in certain situations, those making the choice thought, and still think (or would think, if they were still alive), that this consideration outweighs those of the alternate semantics, even after conscious evaluation.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-12 09:52 +0200 |
| Message-ID | <misbe8$o9f$1@dont-email.me> |
| In reply to | #61875 |
On 12/05/15 05:42, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
<snip>
> The cost I'm talking about is a coding and maintenance cost,
> not a compilation or performance cost. I don't mind agreeing to
> the possibility that your sense of the size of that cost may be
> different from mine.
Fair enough. I don't think we need a discussion about the differences
in such costs in this context - at least, not in this thread.
>>
>> The point of this thread was to ask people with different
>> experiences and styles if they could think of an advantage of the
>> way strcat is defined - precisely because while I could not think
>> of one myself, I thought that someone else might. So far no one
>> (including you) has given any suggestions other than "it seemed a
>> good idea at the time" or "they standardised the function they
>> were using, without thinking about other use-cases". [snip]
>
> My answer may not have been stated very clearly, but I did
> suggest another possible explanation, namely, for reasons you
> don't consider important, namely coding convenience in certain
> situations, those making the choice thought, and still think (or
> would think, if they were still alive), that this consideration
> outweighs those of the alternate semantics, even after conscious
> evaluation.
>
Can you give me:
1. An example where strcat, as defined today, leads to /significantly/
clearer, neater, more maintainable, or more efficient code than a
"strcat2" function that returns a pointer to the end of the string?
2. A justification why you think such coding style was likely in the
early days of C, thus making it a reasonable explanation for the choice
of strcat?
It's very easy to find situations where a strcat2 (returning a pointer
to the end of the string) is clearer and more efficient than strcat.
// Combine three strings and return the total length
int combineStrings(char* s, const char* t1, const char* t2) {
strcat(s, t1); // Time len(s) + len(t1)
strcat(s, t2); // Time len(s) + len(t1) + len(t2)
return strlen(s); // Time len(s) + len(t1) + len(t2)
}
// Total time 3*len(s) + 3*len(t1) + 2*len(t2)
int combineStrings(char* s, const char* t1, const char* t2) {
char* end = strcat2(s, t1); // Time len(s) + len(t1)
end = strcat(end, t2); // Time len(t2)
return end - s; // Time 1
}
// Total time len(s) + len(t1) + len(t2) + 1
(Note that if you really don't like the extra "char* end" variable, you
can use strcat2 exactly like strcat in the first version.)
It is also simpler and more efficient to implement strcat in terms of
strcat2 rather than the reverse:
char * strcat(char* s, const char* t) {
strcat2(s, t); // Time len(s) + len(t)
return s;
}
// Total time len(s) + len(t)
char * strcat2(char* s, const char* t) {
strcat(s, t); // Time len(s) + len(t)
return strlen(s); // Time len(s) + len(t)
}
// Total time 2*len(s) + 2*len(t)
So it is clear that there are common cases where a strcat2 returning the
end pointer is more flexible and significantly more efficient than the
standard version. There are no cases in which the standard version is
more efficient. And the standard version is easily and efficiently
created from the strcat2 version.
The question is, does the standard version lead to significantly neater
or clearer code in common cases, and was it common enough to lead to a
concious design decision when the library was standardised? Or was it,
as most people here seem to think, a bad decision - probably the result
of standardising someone's existing usage rather than the result of a
thoughtful design.
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-05-12 13:33 +0100 |
| Message-ID | <misrtg$m5o$1@dont-email.me> |
| In reply to | #61888 |
On 12/05/2015 08:52, David Brown wrote:
> It's very easy to find situations where a strcat2 (returning a pointer
> to the end of the string) is clearer and more efficient than strcat.
>
> // Combine three strings and return the total length
> int combineStrings(char* s, const char* t1, const char* t2) {
> strcat(s, t1); // Time len(s) + len(t1)
> strcat(s, t2); // Time len(s) + len(t1) + len(t2)
> return strlen(s); // Time len(s) + len(t1) + len(t2)
> }
> // Total time 3*len(s) + 3*len(t1) + 2*len(t2)
>
>
> int combineStrings(char* s, const char* t1, const char* t2) {
> char* end = strcat2(s, t1); // Time len(s) + len(t1)
> end = strcat(end, t2); // Time len(t2)
> return end - s; // Time 1
> }
> // Total time len(s) + len(t1) + len(t2) + 1
In this case you might as well use strlen() on each string, and use
memcpy functions instead.
In fact, if you're going to work with string lengths, the chances are
that these are already available from prior operations on the three
strings, so you might only need to call strlen 0, 1 or 2 times instead of 3.
Perhaps that was the original idea: either use explicit lengths, or work
more elegantly with pure zero-terminated strings.
--
Bartc
[toc] | [prev] | [next] | [standalone]
| From | Ike Naar <ike@iceland.freeshell.org> |
|---|---|
| Date | 2015-05-14 20:15 +0000 |
| Message-ID | <slrn3vfsmla0li.foe.ike@iceland.freeshell.org> |
| In reply to | #61888 |
On 2015-05-12, David Brown <david.brown@hesbynett.no> wrote:
> It's very easy to find situations where a strcat2 (returning a pointer
> to the end of the string) is clearer and more efficient than strcat.
>
> // Combine three strings and return the total length
> int combineStrings(char* s, const char* t1, const char* t2) {
> strcat(s, t1); // Time len(s) + len(t1)
> strcat(s, t2); // Time len(s) + len(t1) + len(t2)
> return strlen(s); // Time len(s) + len(t1) + len(t2)
> }
> // Total time 3*len(s) + 3*len(t1) + 2*len(t2)
>
>
> int combineStrings(char* s, const char* t1, const char* t2) {
> char* end = strcat2(s, t1); // Time len(s) + len(t1)
> end = strcat(end, t2); // Time len(t2)
Shouldn't that be strcat2(end, t2) ?
> return end - s; // Time 1
> }
> // Total time len(s) + len(t1) + len(t2) + 1
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-14 23:06 +0200 |
| Message-ID | <mj32nc$cbt$1@dont-email.me> |
| In reply to | #62019 |
On 14/05/15 22:15, Ike Naar wrote:
> On 2015-05-12, David Brown <david.brown@hesbynett.no> wrote:
>> It's very easy to find situations where a strcat2 (returning a pointer
>> to the end of the string) is clearer and more efficient than strcat.
>>
>> // Combine three strings and return the total length
>> int combineStrings(char* s, const char* t1, const char* t2) {
>> strcat(s, t1); // Time len(s) + len(t1)
>> strcat(s, t2); // Time len(s) + len(t1) + len(t2)
>> return strlen(s); // Time len(s) + len(t1) + len(t2)
>> }
>> // Total time 3*len(s) + 3*len(t1) + 2*len(t2)
>>
>>
>> int combineStrings(char* s, const char* t1, const char* t2) {
>> char* end = strcat2(s, t1); // Time len(s) + len(t1)
>> end = strcat(end, t2); // Time len(t2)
>
> Shouldn't that be strcat2(end, t2) ?
Of course. Sorry.
>
>> return end - s; // Time 1
>> }
>> // Total time len(s) + len(t1) + len(t2) + 1
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-05-20 11:08 -0700 |
| Message-ID | <kfn617nazqd.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #61888 |
David Brown <david.brown@hesbynett.no> writes:
> On 12/05/15 05:42, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>
> <snip>
>
>> The cost I'm talking about is a coding and maintenance cost,
>> not a compilation or performance cost. I don't mind agreeing to
>> the possibility that your sense of the size of that cost may be
>> different from mine.
>
> Fair enough. I don't think we need a discussion about the differences
> in such costs in this context - at least, not in this thread.
>
>>> The point of this thread was to ask people with different
>>> experiences and styles if they could think of an advantage of the
>>> way strcat is defined - precisely because while I could not think
>>> of one myself, I thought that someone else might. So far no one
>>> (including you) has given any suggestions other than "it seemed a
>>> good idea at the time" or "they standardised the function they
>>> were using, without thinking about other use-cases". [snip]
>>
>> My answer may not have been stated very clearly, but I did
>> suggest another possible explanation, namely, for reasons you
>> don't consider important, namely coding convenience in certain
>> situations, those making the choice thought, and still think (or
>> would think, if they were still alive), that this consideration
>> outweighs those of the alternate semantics, even after conscious
>> evaluation.
>
> Can you give me:
>
> 1. An example where strcat, as defined today, leads to /significantly/
> clearer, neater, more maintainable, or more efficient code than a
> "strcat2" function that returns a pointer to the end of the string?
>
> 2. A justification why you think such coding style was likely in the
> early days of C, thus making it a reasonable explanation for the
> choice of strcat?
No, I'm not offering either of those. I'm not saying the reasons
mentioned are ones you would find convincing, only that is it
plausible that the original designers found them convincing.
> It's very easy to find situations where a strcat2 (returning a pointer
> to the end of the string) is clearer and more efficient than strcat.
>
> // Combine three strings and return the total length
> int combineStrings(char* s, const char* t1, const char* t2) {
> strcat(s, t1); // Time len(s) + len(t1)
> strcat(s, t2); // Time len(s) + len(t1) + len(t2)
> return strlen(s); // Time len(s) + len(t1) + len(t2)
> }
> // Total time 3*len(s) + 3*len(t1) + 2*len(t2)
>
>
> int combineStrings(char* s, const char* t1, const char* t2) {
> char* end = strcat2(s, t1); // Time len(s) + len(t1)
> end = strcat(end, t2); // Time len(t2)
> return end - s; // Time 1
> }
> // Total time len(s) + len(t1) + len(t2) + 1
>
> (Note that if you really don't like the extra "char* end" variable, you
> can use strcat2 exactly like strcat in the first version.)
These examples don't seem very compelling to me, because what the
functions do seems somewhat contrived, and because they don't
match how I expect they would be written, especially if
efficiency concerns were paramount. (I assume you meant strcat2
rather than strcat in the second definition.)
> It is also simpler and more efficient to implement strcat in terms of
> strcat2 rather than the reverse:
>
> char * strcat(char* s, const char* t) {
> strcat2(s, t); // Time len(s) + len(t)
> return s;
> }
> // Total time len(s) + len(t)
>
> char * strcat2(char* s, const char* t) {
> strcat(s, t); // Time len(s) + len(t)
> return strlen(s); // Time len(s) + len(t)
> }
> // Total time 2*len(s) + 2*len(t)
I might agree on the "more efficient" part, but not on "simpler"
part.
> So it is clear that there are common cases where a strcat2 returning the
> end pointer is more flexible and significantly more efficient than the
> standard version. There are no cases in which the standard version is
> more efficient. And the standard version is easily and efficiently
> created from the strcat2 version.
I understand that you think this reasoning is convincing. Not
everyone does.
> The question is, does the standard version lead to significantly neater
> or clearer code in common cases, and was it common enough to lead to a
> concious design decision when the library was standardised? Or was it,
> as most people here seem to think, a bad decision - probably the result
> of standardising someone's existing usage rather than the result of a
> thoughtful design.
Why do you find it so hard to believe that other people might
reasonably reach different conclusions than you do?
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-21 10:55 +0200 |
| Message-ID | <mjk6gm$67f$1@dont-email.me> |
| In reply to | #62366 |
On 20/05/15 20:08, Tim Rentsch wrote:
> David Brown <david.brown@hesbynett.no> writes:
>
>> On 12/05/15 05:42, Tim Rentsch wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>
>> <snip>
>>
>>> The cost I'm talking about is a coding and maintenance cost,
>>> not a compilation or performance cost. I don't mind agreeing to
>>> the possibility that your sense of the size of that cost may be
>>> different from mine.
>>
>> Fair enough. I don't think we need a discussion about the differences
>> in such costs in this context - at least, not in this thread.
>>
>>>> The point of this thread was to ask people with different
>>>> experiences and styles if they could think of an advantage of the
>>>> way strcat is defined - precisely because while I could not think
>>>> of one myself, I thought that someone else might. So far no one
>>>> (including you) has given any suggestions other than "it seemed a
>>>> good idea at the time" or "they standardised the function they
>>>> were using, without thinking about other use-cases". [snip]
>>>
>>> My answer may not have been stated very clearly, but I did
>>> suggest another possible explanation, namely, for reasons you
>>> don't consider important, namely coding convenience in certain
>>> situations, those making the choice thought, and still think (or
>>> would think, if they were still alive), that this consideration
>>> outweighs those of the alternate semantics, even after conscious
>>> evaluation.
>>
>> Can you give me:
>>
>> 1. An example where strcat, as defined today, leads to /significantly/
>> clearer, neater, more maintainable, or more efficient code than a
>> "strcat2" function that returns a pointer to the end of the string?
>>
>> 2. A justification why you think such coding style was likely in the
>> early days of C, thus making it a reasonable explanation for the
>> choice of strcat?
>
> No, I'm not offering either of those. I'm not saying the reasons
> mentioned are ones you would find convincing, only that is it
> plausible that the original designers found them convincing.
I realise that - that's why I asked you for a justification for why you
think the original designers did it this way. But I am not yet
convinced that the original designers thought this through properly. I
can accept that they might have had different balances between
efficiency and simplicity, or compilers with different abilities, or
different styles. However, I am still lacking /any/ justification for
suggesting the original library designers thought "strcat" was a better
choice than "strcat2". Currently, it appears that they simply didn't
consider the issues. (And that's fair enough - we can't expect them to
have had perfect hindsight when starting out. We must simply live with
it as another of C's sub-optimal design decisions.)
>
>> It's very easy to find situations where a strcat2 (returning a pointer
>> to the end of the string) is clearer and more efficient than strcat.
>>
>> // Combine three strings and return the total length
>> int combineStrings(char* s, const char* t1, const char* t2) {
>> strcat(s, t1); // Time len(s) + len(t1)
>> strcat(s, t2); // Time len(s) + len(t1) + len(t2)
>> return strlen(s); // Time len(s) + len(t1) + len(t2)
>> }
>> // Total time 3*len(s) + 3*len(t1) + 2*len(t2)
>>
>>
>> int combineStrings(char* s, const char* t1, const char* t2) {
>> char* end = strcat2(s, t1); // Time len(s) + len(t1)
>> end = strcat(end, t2); // Time len(t2)
>> return end - s; // Time 1
>> }
>> // Total time len(s) + len(t1) + len(t2) + 1
>>
>> (Note that if you really don't like the extra "char* end" variable, you
>> can use strcat2 exactly like strcat in the first version.)
>
> These examples don't seem very compelling to me, because what the
> functions do seems somewhat contrived, and because they don't
> match how I expect they would be written, especially if
> efficiency concerns were paramount. (I assume you meant strcat2
> rather than strcat in the second definition.)
They are simply example functions that demonstrate the difference
between strcat and strcat2 when combining several strings. Feel free to
write them in a more efficient form - once using the standard strcat,
strcpy, strlen functions, and once using strcat2. No loops to manually
copy the strings are allowed (because that would be missing the point of
having the library functions). I am curious to see how you would write
them with greater efficiency.
>
>> It is also simpler and more efficient to implement strcat in terms of
>> strcat2 rather than the reverse:
>>
>> char * strcat(char* s, const char* t) {
>> strcat2(s, t); // Time len(s) + len(t)
>> return s;
>> }
>> // Total time len(s) + len(t)
>>
>> char * strcat2(char* s, const char* t) {
>> strcat(s, t); // Time len(s) + len(t)
>> return strlen(s); // Time len(s) + len(t)
>> }
>> // Total time 2*len(s) + 2*len(t)
>
> I might agree on the "more efficient" part, but not on "simpler"
> part.
You cannot possibly /disagree/ on the "more efficient" part - strcat can
be implemented optimally from strcat2, while the opposite direction
requires double the time. (In theory, a smart enough compiler could
remove the function calls and turn the strcat + strlen into an inlined
loop.)
And how can you justify contending on the "simpler" part? Implementing
strcat from strcat2 requires one function call, while implementing
strcat2 from strcat requires two function calls. I won't claim it's a
complicated function, but there can be no doubts as to which is simpler.
>
>> So it is clear that there are common cases where a strcat2 returning the
>> end pointer is more flexible and significantly more efficient than the
>> standard version. There are no cases in which the standard version is
>> more efficient. And the standard version is easily and efficiently
>> created from the strcat2 version.
>
> I understand that you think this reasoning is convincing. Not
> everyone does.
I have given a fair amount of justification and evidence for why my
reasoning makes sense. I still have heard absolutely no technical
justification for the choice of strcat as we have it today, compared to
strcat2 (or a version that returned the length of the new string, which
would be another reasonable alternative). You have done nothing but
claim that the original library authors might have had good reason for
the decision.
>
>> The question is, does the standard version lead to significantly neater
>> or clearer code in common cases, and was it common enough to lead to a
>> concious design decision when the library was standardised? Or was it,
>> as most people here seem to think, a bad decision - probably the result
>> of standardising someone's existing usage rather than the result of a
>> thoughtful design.
>
> Why do you find it so hard to believe that other people might
> reasonably reach different conclusions than you do?
>
I like to base my conclusions on evidence and technical justifications,
if I can. I can find plenty of evidence for the viewpoint that strcat2
would have been a better choice for the standard library than strcat. I
can find no significant evidence to the contrary, and no one else here
seems to have done so either.
The nearest I have seen is the fact that strcat allows certain chained
expression syntaxes that cannot be written directly with strcat2 - you
need to use multiple expressions. But even in such cases, the strcat2
version is not more difficult, and it is much more efficient. And no
one has argued that such chained expressions were common in old C code,
or that they were a reason for picking the strcat form.
So the question is, why do you find it so hard to believe that the
original design decision was not a good one, and was perhaps made in
haste or for "historical" reasons?
[toc] | [prev] | [next] | [standalone]
| From | glen herrmannsfeldt <gah@ugcs.caltech.edu> |
|---|---|
| Date | 2015-05-21 13:05 +0000 |
| Message-ID | <mjkl6i$brf$1@speranza.aioe.org> |
| In reply to | #62395 |
David Brown <david.brown@hesbynett.no> wrote: > On 20/05/15 20:08, Tim Rentsch wrote: >> David Brown <david.brown@hesbynett.no> writes: (snip, someone wrote) >>> Can you give me: >>> 1. An example where strcat, as defined today, leads to /significantly/ >>> clearer, neater, more maintainable, or more efficient code than a >>> "strcat2" function that returns a pointer to the end of the string? An important word above is "today". strcat wasn't designed recently, and hardware was a lot different when it was. Decisions that are right today, may not have been right 40 years ago. >>> 2. A justification why you think such coding style was likely in the >>> early days of C, thus making it a reasonable explanation for the >>> choice of strcat? >> No, I'm not offering either of those. I'm not saying the reasons >> mentioned are ones you would find convincing, only that is it >> plausible that the original designers found them convincing. That was just at the transitions from writing operating systems, and even compilers, in the appropriate assembly language, possibly with various aids to make it easier, to writing them in high level languages. Multics is, as I understand it, mostly PL/I. C and unix were for smaller computers. It is mostly that we, today, decided to take what was optimal for small computers and assume it optimal for large ones. > I realise that - that's why I asked you for a justification for why you > think the original designers did it this way. But I am not yet > convinced that the original designers thought this through properly. I > can accept that they might have had different balances between > efficiency and simplicity, or compilers with different abilities, or > different styles. However, I am still lacking /any/ justification for > suggesting the original library designers thought "strcat" was a better > choice than "strcat2". Currently, it appears that they simply didn't > consider the issues. (And that's fair enough - we can't expect them to > have had perfect hindsight when starting out. We must simply live with > it as another of C's sub-optimal design decisions.) The inefficiency of strcat() is O(n*n). (O(n**2) in some newsgroups.) (I had to actually debug a program once where someone had used strcat() in a loop, where actual O(n**2) timing was visible.) When n=10, you don't notice, and the existing strcat() may be optimal. >>> It's very easy to find situations where a strcat2 (returning a pointer >>> to the end of the string) is clearer and more efficient than strcat. (snip) >> These examples don't seem very compelling to me, because what the >> functions do seems somewhat contrived, and because they don't >> match how I expect they would be written, especially if >> efficiency concerns were paramount. (I assume you meant strcat2 >> rather than strcat in the second definition.) > They are simply example functions that demonstrate the difference > between strcat and strcat2 when combining several strings. Feel free to > write them in a more efficient form - once using the standard strcat, > strcpy, strlen functions, and once using strcat2. No loops to manually > copy the strings are allowed (because that would be missing the point of > having the library functions). I am curious to see how you would write > them with greater efficiency. In the actual case mentioned above, I used strlen() and strcpy(). Using strlen() allowed me to verify that the new string would fit. >>> It is also simpler and more efficient to implement strcat in terms of >>> strcat2 rather than the reverse: (snip) >> I might agree on the "more efficient" part, but not on "simpler" >> part. In many cases, strcat() or strcat2() aren't good choices. They work well when you can be reasonably (enough) sure that you won't outrun the array. If you can't, there are easier ways than to test first and then strcat(). > You cannot possibly /disagree/ on the "more efficient" part - strcat can > be implemented optimally from strcat2, while the opposite direction > requires double the time. (In theory, a smart enough compiler could > remove the function calls and turn the strcat + strlen into an inlined > loop.) As above, I suspect original strcat() was used closer to n=10. It is nice when you want to add an extension onto a file name. You might: x=fopen(strcat(file,".xyz"),"w"); It is not nice when you want to read in megabytes of data, one screen-width line at a time. > And how can you justify contending on the "simpler" part? Implementing > strcat from strcat2 requires one function call, while implementing > strcat2 from strcat requires two function calls. I won't claim it's a > complicated function, but there can be no doubts as to which is simpler. (snip) >> I understand that you think this reasoning is convincing. Not >> everyone does. > I have given a fair amount of justification and evidence for why my > reasoning makes sense. I still have heard absolutely no technical > justification for the choice of strcat as we have it today, compared to > strcat2 (or a version that returned the length of the new string, which > would be another reasonable alternative). You have done nothing but > claim that the original library authors might have had good reason for > the decision. Your reasoning might make sense today, but maybe not 40 years ago. I don't know by now, maybe someone does, was the original strcat() written in C, or the appropriate assembly? >>> The question is, does the standard version lead to significantly neater >>> or clearer code in common cases, and was it common enough to lead to a >>> concious design decision when the library was standardised? Or was it, >>> as most people here seem to think, a bad decision - probably the result >>> of standardising someone's existing usage rather than the result of a >>> thoughtful design. >> Why do you find it so hard to believe that other people might >> reasonably reach different conclusions than you do? If you haven't read K&R1, you should do that. That should give you a better idea of what the original designers of C expected it to do. How they thought it might be used. > I like to base my conclusions on evidence and technical justifications, > if I can. I can find plenty of evidence for the viewpoint that strcat2 > would have been a better choice for the standard library than strcat. I > can find no significant evidence to the contrary, and no one else here > seems to have done so either. Well, for one, many C library string routines return a pointer to the first argument. It is nice to have a little consistency. > The nearest I have seen is the fact that strcat allows certain chained > expression syntaxes that cannot be written directly with strcat2 - you > need to use multiple expressions. But even in such cases, the strcat2 > version is not more difficult, and it is much more efficient. And no > one has argued that such chained expressions were common in old C code, > or that they were a reason for picking the strcat form. > So the question is, why do you find it so hard to believe that the > original design decision was not a good one, and was perhaps made in > haste or for "historical" reasons? I suspect that if you asked the original C designers, at the time, if they expected C to be popular 40 years later, they would have said "no". Not that they didn't believe in their design, but there are many people out there with good ideas. Statistically, it wasn't so likely to happen. -- glen
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2015-05-21 20:42 +0200 |
| Message-ID | <mjl8se$b51$1@dont-email.me> |
| In reply to | #62402 |
On 21/05/15 15:05, glen herrmannsfeldt wrote: > David Brown <david.brown@hesbynett.no> wrote: >> On 20/05/15 20:08, Tim Rentsch wrote: >>> David Brown <david.brown@hesbynett.no> writes: > (snip, someone wrote) >>>> Can you give me: > >>>> 1. An example where strcat, as defined today, leads to /significantly/ >>>> clearer, neater, more maintainable, or more efficient code than a >>>> "strcat2" function that returns a pointer to the end of the string? > > An important word above is "today". strcat wasn't designed recently, > and hardware was a lot different when it was. Decisions that are > right today, may not have been right 40 years ago. I agree - and that is part of the reason for this thread in the first place. Was there something about the hardware, or the way compilers worked, or the style used by early C programmers, that made the standard strcat definition a better choice than the strcat2 version returning a pointer to the end of the string (or alternatively, a version returning the length of the string)? The same arguments about the efficiency of strcat2 compared to strcat applied 40 years ago. Saying that it is /possible/ that strcat was a better choice than strcat2 40 years ago does not mean it was actually the case. > >>>> 2. A justification why you think such coding style was likely in the >>>> early days of C, thus making it a reasonable explanation for the >>>> choice of strcat? > >>> No, I'm not offering either of those. I'm not saying the reasons >>> mentioned are ones you would find convincing, only that is it >>> plausible that the original designers found them convincing. > > That was just at the transitions from writing operating systems, > and even compilers, in the appropriate assembly language, possibly > with various aids to make it easier, to writing them in high level > languages. Multics is, as I understand it, mostly PL/I. > > C and unix were for smaller computers. It is mostly that we, today, > decided to take what was optimal for small computers and assume it > optimal for large ones. strcat2 is a much more efficient choice than strcat for small systems as well as big ones. So that argument does not hold much water (although it might possibly apply to other C design decisions that are not ideal when viewed in a modern light). > >> I realise that - that's why I asked you for a justification for why you >> think the original designers did it this way. But I am not yet >> convinced that the original designers thought this through properly. I >> can accept that they might have had different balances between >> efficiency and simplicity, or compilers with different abilities, or >> different styles. However, I am still lacking /any/ justification for >> suggesting the original library designers thought "strcat" was a better >> choice than "strcat2". Currently, it appears that they simply didn't >> consider the issues. (And that's fair enough - we can't expect them to >> have had perfect hindsight when starting out. We must simply live with >> it as another of C's sub-optimal design decisions.) > > The inefficiency of strcat() is O(n*n). (O(n**2) in some newsgroups.) > > (I had to actually debug a program once where someone had used > strcat() in a loop, where actual O(n**2) timing was visible.) > > When n=10, you don't notice, and the existing strcat() may be > optimal. You might not notice it when n = 10, and for small sizes on old processors (with larger function-call overheads), the wasted time gets lost in the "noise" of all the other time spent in the code. > >>>> It's very easy to find situations where a strcat2 (returning a pointer >>>> to the end of the string) is clearer and more efficient than strcat. > > (snip) > >>> These examples don't seem very compelling to me, because what the >>> functions do seems somewhat contrived, and because they don't >>> match how I expect they would be written, especially if >>> efficiency concerns were paramount. (I assume you meant strcat2 >>> rather than strcat in the second definition.) > >> They are simply example functions that demonstrate the difference >> between strcat and strcat2 when combining several strings. Feel free to >> write them in a more efficient form - once using the standard strcat, >> strcpy, strlen functions, and once using strcat2. No loops to manually >> copy the strings are allowed (because that would be missing the point of >> having the library functions). I am curious to see how you would write >> them with greater efficiency. > > In the actual case mentioned above, I used strlen() and strcpy(). > Using strlen() allowed me to verify that the new string would fit. > >>>> It is also simpler and more efficient to implement strcat in terms of >>>> strcat2 rather than the reverse: > > (snip) >>> I might agree on the "more efficient" part, but not on "simpler" >>> part. > > In many cases, strcat() or strcat2() aren't good choices. > > They work well when you can be reasonably (enough) sure that you > won't outrun the array. If you can't, there are easier ways than > to test first and then strcat(). If you have the length in advance, then of course you can use something like memcpy() rather than strcat(). But sometimes you know your limits are safe even though you don't know exact lengths (or, like many early C programmers and a few modern ones, you simply ignore the risks of buffer overflow!). > >> You cannot possibly /disagree/ on the "more efficient" part - strcat can >> be implemented optimally from strcat2, while the opposite direction >> requires double the time. (In theory, a smart enough compiler could >> remove the function calls and turn the strcat + strlen into an inlined >> loop.) > > As above, I suspect original strcat() was used closer to n=10. > It is nice when you want to add an extension onto a file name. > You might: > > x=fopen(strcat(file,".xyz"),"w"); > > It is not nice when you want to read in megabytes of data, one > screen-width line at a time. > >> And how can you justify contending on the "simpler" part? Implementing >> strcat from strcat2 requires one function call, while implementing >> strcat2 from strcat requires two function calls. I won't claim it's a >> complicated function, but there can be no doubts as to which is simpler. > (snip) > >>> I understand that you think this reasoning is convincing. Not >>> everyone does. > >> I have given a fair amount of justification and evidence for why my >> reasoning makes sense. I still have heard absolutely no technical >> justification for the choice of strcat as we have it today, compared to >> strcat2 (or a version that returned the length of the new string, which >> would be another reasonable alternative). You have done nothing but >> claim that the original library authors might have had good reason for >> the decision. > > Your reasoning might make sense today, but maybe not 40 years ago. > > I don't know by now, maybe someone does, was the original strcat() > written in C, or the appropriate assembly? > >>>> The question is, does the standard version lead to significantly neater >>>> or clearer code in common cases, and was it common enough to lead to a >>>> concious design decision when the library was standardised? Or was it, >>>> as most people here seem to think, a bad decision - probably the result >>>> of standardising someone's existing usage rather than the result of a >>>> thoughtful design. > >>> Why do you find it so hard to believe that other people might >>> reasonably reach different conclusions than you do? > > If you haven't read K&R1, you should do that. That should give > you a better idea of what the original designers of C expected > it to do. How they thought it might be used. I have read it, but it was a /long/ time ago - perhaps 25 years. > >> I like to base my conclusions on evidence and technical justifications, >> if I can. I can find plenty of evidence for the viewpoint that strcat2 >> would have been a better choice for the standard library than strcat. I >> can find no significant evidence to the contrary, and no one else here >> seems to have done so either. > > Well, for one, many C library string routines return a pointer to the > first argument. It is nice to have a little consistency. > >> The nearest I have seen is the fact that strcat allows certain chained >> expression syntaxes that cannot be written directly with strcat2 - you >> need to use multiple expressions. But even in such cases, the strcat2 >> version is not more difficult, and it is much more efficient. And no >> one has argued that such chained expressions were common in old C code, >> or that they were a reason for picking the strcat form. > >> So the question is, why do you find it so hard to believe that the >> original design decision was not a good one, and was perhaps made in >> haste or for "historical" reasons? > > I suspect that if you asked the original C designers, at the time, > if they expected C to be popular 40 years later, they would have > said "no". Not that they didn't believe in their design, but there > are many people out there with good ideas. Statistically, it wasn't > so likely to happen. > True enough.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-07-10 10:40 -0700 |
| Message-ID | <kfnbnfj6hd6.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #62395 |
David Brown <david.brown@hesbynett.no> writes:
> On 20/05/15 20:08, Tim Rentsch wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> On 12/05/15 05:42, Tim Rentsch wrote:
>>>> David Brown <david.brown@hesbynett.no> writes:
>>>
>>> <snip>
>>>
>>>> The cost I'm talking about is a coding and maintenance cost,
>>>> not a compilation or performance cost. I don't mind agreeing to
>>>> the possibility that your sense of the size of that cost may be
>>>> different from mine.
>>>
>>> Fair enough. I don't think we need a discussion about the differences
>>> in such costs in this context - at least, not in this thread.
>>>
>>>>> The point of this thread was to ask people with different
>>>>> experiences and styles if they could think of an advantage of the
>>>>> way strcat is defined - precisely because while I could not think
>>>>> of one myself, I thought that someone else might. So far no one
>>>>> (including you) has given any suggestions other than "it seemed a
>>>>> good idea at the time" or "they standardised the function they
>>>>> were using, without thinking about other use-cases". [snip]
>>>>
>>>> My answer may not have been stated very clearly, but I did
>>>> suggest another possible explanation, namely, for reasons you
>>>> don't consider important, namely coding convenience in certain
>>>> situations, those making the choice thought, and still think (or
>>>> would think, if they were still alive), that this consideration
>>>> outweighs those of the alternate semantics, even after conscious
>>>> evaluation.
>>>
>>> Can you give me:
>>>
>>> 1. An example where strcat, as defined today, leads to /significantly/
>>> clearer, neater, more maintainable, or more efficient code than a
>>> "strcat2" function that returns a pointer to the end of the string?
>>>
>>> 2. A justification why you think such coding style was likely in the
>>> early days of C, thus making it a reasonable explanation for the
>>> choice of strcat?
>>
>> No, I'm not offering either of those. I'm not saying the reasons
>> mentioned are ones you would find convincing, only that is it
>> plausible that the original designers found them convincing.
>
> I realise that - that's why I asked you for a justification for why you
> think the original designers did it this way. But I am not yet
> convinced that the original designers thought this through properly. I
> can accept that they might have had different balances between
> efficiency and simplicity, or compilers with different abilities, or
> different styles. However, I am still lacking /any/ justification for
> suggesting the original library designers thought "strcat" was a better
> choice than "strcat2". Currently, it appears that they simply didn't
> consider the issues. (And that's fair enough - we can't expect them to
> have had perfect hindsight when starting out. We must simply live with
> it as another of C's sub-optimal design decisions.)
What you mean is you're lacking a justification you find convincing.
That's not quite the same thing.
>>> It's very easy to find situations where a strcat2 (returning a pointer
>>> to the end of the string) is clearer and more efficient than strcat.
>>>
>>> // Combine three strings and return the total length
>>> int combineStrings(char* s, const char* t1, const char* t2) {
>>> strcat(s, t1); // Time len(s) + len(t1)
>>> strcat(s, t2); // Time len(s) + len(t1) + len(t2)
>>> return strlen(s); // Time len(s) + len(t1) + len(t2)
>>> }
>>> // Total time 3*len(s) + 3*len(t1) + 2*len(t2)
>>>
>>>
>>> int combineStrings(char* s, const char* t1, const char* t2) {
>>> char* end = strcat2(s, t1); // Time len(s) + len(t1)
>>> end = strcat(end, t2); // Time len(t2)
>>> return end - s; // Time 1
>>> }
>>> // Total time len(s) + len(t1) + len(t2) + 1
>>>
>>> (Note that if you really don't like the extra "char* end" variable, you
>>> can use strcat2 exactly like strcat in the first version.)
>>
>> These examples don't seem very compelling to me, because what the
>> functions do seems somewhat contrived, and because they don't
>> match how I expect they would be written, especially if
>> efficiency concerns were paramount. (I assume you meant strcat2
>> rather than strcat in the second definition.)
>
> They are simply example functions that demonstrate the difference
> between strcat and strcat2 when combining several strings. Feel free to
> write them in a more efficient form - once using the standard strcat,
> strcpy, strlen functions, and once using strcat2. No loops to manually
> copy the strings are allowed (because that would be missing the point of
> having the library functions). I am curious to see how you would write
> them with greater efficiency.
I don't see the point of (re-)writing them, because I don't think
the problem they are solving illustrates anything useful.
>>> It is also simpler and more efficient to implement strcat in terms of
>>> strcat2 rather than the reverse:
>>>
>>> char * strcat(char* s, const char* t) {
>>> strcat2(s, t); // Time len(s) + len(t)
>>> return s;
>>> }
>>> // Total time len(s) + len(t)
>>>
>>> char * strcat2(char* s, const char* t) {
>>> strcat(s, t); // Time len(s) + len(t)
>>> return strlen(s); // Time len(s) + len(t)
>>> }
>>> // Total time 2*len(s) + 2*len(t)
>>
>> I might agree on the "more efficient" part, but not on "simpler"
>> part.
>
> You cannot possibly /disagree/ on the "more efficient" part - strcat can
> be implemented optimally from strcat2, while the opposite direction
> requires double the time. (In theory, a smart enough compiler could
> remove the function calls and turn the strcat + strlen into an inlined
> loop.)
Now that's funny. You point out a line of reasoning that pokes
a hole in your assertion, immediately after saying I can't
possibly have such a line of reasoning. Good one. :)
> And how can you justify contending on the "simpler" part? Implementing
> strcat from strcat2 requires one function call, while implementing
> strcat2 from strcat requires two function calls. I won't claim it's a
> complicated function, but there can be no doubts as to which is simpler.
Obviously we have different "simpleness" metrics; in my metric
they are (roughly) equally simple. Also it doesn't help your
case that one of the definitions has a (deliberate?) bug.
>>> So it is clear that there are common cases where a strcat2 returning the
>>> end pointer is more flexible and significantly more efficient than the
>>> standard version. There are no cases in which the standard version is
>>> more efficient. And the standard version is easily and efficiently
>>> created from the strcat2 version.
>>
>> I understand that you think this reasoning is convincing. Not
>> everyone does.
>
> I have given a fair amount of justification and evidence for why my
> reasoning makes sense. I still have heard absolutely no technical
> justification for the choice of strcat as we have it today, compared to
> strcat2 (or a version that returned the length of the new string, which
> would be another reasonable alternative). You have done nothing but
> claim that the original library authors might have had good reason for
> the decision.
Again, you haven't heard a justtification that convinvices you.
That isn't the same as saying no justification has been offered.
>>> The question is, does the standard version lead to significantly neater
>>> or clearer code in common cases, and was it common enough to lead to a
>>> concious design decision when the library was standardised? Or was it,
>>> as most people here seem to think, a bad decision - probably the result
>>> of standardising someone's existing usage rather than the result of a
>>> thoughtful design.
>>
>> Why do you find it so hard to believe that other people might
>> reasonably reach different conclusions than you do?
>
> I like to base my conclusions on evidence and technical justifications,
> if I can. I can find plenty of evidence for the viewpoint that strcat2
> would have been a better choice for the standard library than strcat. I
> can find no significant evidence to the contrary, and no one else here
> seems to have done so either.
>
> The nearest I have seen is the fact that strcat allows certain chained
> expression syntaxes that cannot be written directly with strcat2 - you
> need to use multiple expressions. But even in such cases, the strcat2
> version is not more difficult, and it is much more efficient. And no
> one has argued that such chained expressions were common in old C code,
> or that they were a reason for picking the strcat form.
I'm sorry I wasn't better able to communicate the point I was
trying to make.
> So the question is, why do you find it so hard to believe that the
> original design decision was not a good one, and was perhaps made in
> haste or for "historical" reasons?
It's important to distinguish two different situations. I don't
find it hard to believe the original design process for strcat()
etc _might_ not be so good. But that is very different from
concluding that the original design process was _not_ good.
My complaint is that you appear not to differentiate between
these two circumstances.
[toc] | [prev] | [next] | [standalone]
| From | raltbos@xs4all.nl (Richard Bos) |
|---|---|
| Date | 2015-05-08 21:56 +0000 |
| Message-ID | <554d3048.37036515@news.xs4all.nl> |
| In reply to | #61654 |
Tim Rentsch <txr@alumni.caltech.edu> wrote: > David Brown <david.brown@hesbynett.no> writes: > > > Does anyone know why the return value for strcat and similar library > > functions is defined in such an unhelpful (IMHO) way? > > > > The return value of strcat(s1, s2) is always s1, which is a value you > > already have available. Returning a pointer to the end of s1 (i.e., s1 > > + strlen(s1)) would be much more efficient when building up a string > > from parts. > > You're assuming that the value of the first argument is readily > available otherwise, which isn't always true - it could be the > result of a function call, for example. The value of the first argument is always either readily available or readily _made_ available. The desired return value, the _end_ of the string rather than the already given start of it, is not, except from within the function. I, too, would have preferred to get the latter value from strfoo(), and if I ever get around to draw up the specifications for my very perfect C-with-hindsight (a.k.a. C 2020), they will - but in C, they don't. For this, as far as the Standard is concerned, I fear the blame lays squarely at the feet of that old monster, Previous Art; why Art did it this way, Paul may know, but I don't. Possibly laziness. Richard
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-05-10 09:07 -0700 |
| Message-ID | <kfnzj5ce7qh.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #61790 |
raltbos@xs4all.nl (Richard Bos) writes:
> Tim Rentsch <txr@alumni.caltech.edu> wrote:
>
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> Does anyone know why the return value for strcat and similar
>>> library functions is defined in such an unhelpful (IMHO) way?
>>>
>>> The return value of strcat(s1, s2) is always s1, which is a value
>>> you already have available. Returning a pointer to the end of s1
>>> (i.e., s1 + strlen(s1)) would be much more efficient when building
>>> up a string from parts.
>>
>> You're assuming that the value of the first argument is readily
>> available otherwise, which isn't always true - it could be the
>> result of a function call, for example.
>
> The value of the first argument is always either readily available
> or readily _made_ available. The desired return value, the _end_
> of the string rather than the already given start of it, is not,
> except from within the function.
I agree the value is always either readily available or can be
made available by declaring a name to hold the value. Either
way, the result can be clunky if what you want to do is pass
the value on to another expression in a more functional style,
which the current semantics supports.
> I, too, would have preferred to get the latter value from
> strfoo(), and if I ever get around to draw up the specifications
> for my very perfect C-with-hindsight (a.k.a. C 2020), they will -
> but in C, they don't. For this, as far as the Standard is
> concerned, I fear the blame lays squarely at the feet of that old
> monster, Previous Art; why Art did it this way, Paul may know,
> but I don't. Possibly laziness.
Another possibility is that whoever made the decision thought
supporting a more functional style has value, and made a
conscious choice favoring that over an "end of string" version.
Incidentally, if you want these, both can be provided with
less writing then you did in your followup:
char *
bstrcpy( char *d, const char *s ){
return (*d = *s) ? bstrcpy( d+1, s+1 ) : d;
}
char *
bstrcat( char *d, const char *s ){
return *d ? bstrcat( d+1, s ) : bstrcpy( d, s );
}
[toc] | [prev] | [next] | [standalone]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-05-07 10:11 +0100 |
| Message-ID | <mifa6t$r28$1@dont-email.me> |
| In reply to | #61598 |
On 06/05/2015 09:02, David Brown wrote: > Does anyone know why the return value for strcat and similar library > functions is defined in such an unhelpful (IMHO) way? > > The return value of strcat(s1, s2) is always s1, which is a value you > already have available. Returning a pointer to the end of s1 (i.e., s1 > + strlen(s1)) would be much more efficient when building up a string > from parts. It sounds a little like a deliberate decision to keep string lengths under wraps and not to let the programmer know what they were without explicitly calling strlen(). This might have sounded like an elegant concept back in 1970. After all, if string lengths were available at nearly every stage, then it would tear apart the string library: you'd use memcpy instead of strcpy and strcat; you wouldn't need strcmp half the time (because the lengths were unequal, and for equal lengths you'd use memcmp); it would even obviate the need for a zero terminator in many cases! -- Bartc
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.c
csiph-web