Should function argument be changed in function body?

C

CBFalconer

pete said:
ptr_diff is too small.
Why not just use strlen?

Because all this is illustrations of cases for the subject line,
not practical proposals. You snipped the whole raison d'etre.
 
C

CBFalconer

Tim said:
What connection would that be? Declaring a parameter 'const'
(the parameter itself, not something it points to) doesn't
impose any burden on any call site.

It restricts the freedom of action when revising the function, to
no purpose. We are not talking about pointers here, but actual
value parameters. Modifying them cannot affect anything outside
the function anyhow.
 
C

Chris Croughton

Of course, after all the fuss, this is a function that can be
improved by not altering the input parameter.

size_t length_of_string(const char *s) {
const char *t = s;

while (*t++) continue;
return t - s;
}

(and I will live with the possibility that ptr_diff is too small)

Are there any machines where ptrdiff_t actually is too small?
Presumably on most it will be a signed version of whatever type size_t
is, which is arguably "too small" for really big objects but not in most
practical situations.

The 'counting' version is to make sure that there is no problem,
anyway...

Chris C
 
C

Chris Croughton

ptr_diff is too small.

Do you often have strings over 2GB long? The only systems I know of
where it's likely to be too small in practical uses are a few 16 bit
ones.
Why not just use strlen?

Someone has to implement strlen...

Chris C
 
C

Chris Croughton

I know where you're coming from. What code seems "natural" to
people certainly varies from person to person.

Yes, exactly. There are some people who don't like side-effects and
escew the ++ and -- operators, for instance. De gustibus and all that.
Even though this
example wasn't the best, however, I hope you can see the
principle that I'm trying to illustrate. Consider two versions
of matrix multiplication, for example - one written out using
arrays and normal index calculations, the other using pointer
variables being changed and updated with only plus and minus.
The "less imperative" version that uses arrays and just simple
loops with i,j,k index variables is more likely to be easy
to understand.

Yes, that's true, and I would regard that as a situation which breaks my
complexity threshold for such things.
(I'm assuming you meant to write slightly different code that
returned the same value but caused the destination string to be
null-terminated. Please read the comments below as if that
code were written above.)

Oops. But look how quickly you found the deliberate mistake <g>. There
was meant to be *dst = 0; after the loop...

(Actually, that's one function where I really would like templates as in
C++, put it as an inline template funtion to copy any 'string' of
an appropriate type, integers or wide characters being usual...)
I think we're in agreement that there are cases (the above
probably being one) where modifying the paramters yields a
better-overall function body. Where we may disagree is what
the magnitude of the difference is. The function body above
re-written to use locals rather than modifying its parameters
might be a line or two longer, but I don't think I'd say that
code would obscure things. Perhaps I'm just more used to a
style that almost never modifies parameters.

I think it's a matter of where one draws the limit, rather than a
fundamental difference. Your tolerance for complexity it probably at a
slightly lower level than mine (I started with FORTRAN IV and assembler,
on processors where self-modified code was a normal way of doing jump
tables to save a few memory locations!).
In practice it sounds like our views are actually pretty
similar. I appreciate the comments.

We're not totally opposed, we just draw the lines in different places.
As seen above, I think that you wouldn't have too much problem with most
of my code and I wouldn't have problem with yours, we'd just niggle a
bit about a few frings cases <g>...

Chris C
 
T

Tim Rentsch

CBFalconer said:
It restricts the freedom of action when revising the function, to
no purpose. We are not talking about pointers here, but actual
value parameters. Modifying them cannot affect anything outside
the function anyhow.

You still haven't given any connection between "code modules",
assuming by "code modules" you mean two different sections of
code each at least as big as one function body, which is how I
think most people would read the term.

As to the rest of the comment - lots of people see a benefit in
using 'const' for function-local variables that won't be
modified during function execution. If you choose not to avail
yourself of those benefits, well, that's your prerogative. But
it seems rather silly to say that there are no such benefits.
 
T

Tim Rentsch

Chris Croughton said:
We're not totally opposed, we just draw the lines in different places.
As seen above, I think that you wouldn't have too much problem with most
of my code and I wouldn't have problem with yours, we'd just niggle a
bit about a few frings cases <g>...

I think of modifying function parameters in much the same way
that I think of using goto. Completely undisciplined use of
goto is bad. Beginners need to be steered away from goto
rather emphatically, because if they aren't they tend to
overuse it. After reaching a certain level of experience and
competence, and mainly having acquired the discipline not to
use it unnecessarily, allowing goto's in certain cases seems
acceptable and reasonable. I use goto myself now and then;
but when I do it's a conscious decision made after considering
and comparing non-goto alternatives.
 
M

Mark

Of course, after all the fuss, this is a function that can be
improved by not altering the input parameter.
And by improved, do you mean broken?
size_t length_of_string(const char *s) {
const char *t = s;

while (*t++) continue;
return t - s;
}

(and I will live with the possibility that ptr_diff is too small)

You're also living with the fact that:
printf("%d\n", length_of_string(""));
will print 1.

Luckily it's an easy fix...
while(*t)
++t;

Regards,
Mark
 
C

CBFalconer

Mark said:
And by improved, do you mean broken?


You're also living with the fact that:
printf("%d\n", length_of_string(""));
will print 1.

Woops! Continuing the theme of keeping stuff out of the loop:

return t - s - 1;

seems like a cleaner fix to me :) The alternative is to rename it
as 'storage_needed_for_string', and let it avoid those newbie
malloc errors.
 
C

CBFalconer

Tim said:
You still haven't given any connection between "code modules",
assuming by "code modules" you mean two different sections of
code each at least as big as one function body, which is how I
think most people would read the term.

As to the rest of the comment - lots of people see a benefit in
using 'const' for function-local variables that won't be
modified during function execution. If you choose not to avail
yourself of those benefits, well, that's your prerogative. But
it seems rather silly to say that there are no such benefits.

I've put myself in a peculiar position, for one who espouses Pascal
and the restrictions imposed by strong typing, etc. Here I am
arguing for the elimination of restrictions in C. In part it is
the minimalist in me - I don't want any extra variables declared,
and I don't want any extra restrictions forcing me to so declare.
I consider every extra thing that is needed to be known outside the
connected modules to be a connection. For a normal non-static
function there are three entities involved: The user, the
prototype, and the function. For minimal connectivity there should
be minimal restrictions on the user and the function. In general
we can consider the prototype to be the longest lived of all.

Maybe this makes sense.
 
C

Chris Croughton

And by improved, do you mean broken?


You're also living with the fact that:
printf("%d\n", length_of_string(""));
will print 1.

Actually, it will exhibit undefined behaviour since the function returns
size_t and %d expects an int...

Since we're being picky, and all...

Chris C
 
C

Chris Croughton

I think of modifying function parameters in much the same way
that I think of using goto. Completely undisciplined use of
goto is bad. Beginners need to be steered away from goto
rather emphatically, because if they aren't they tend to
overuse it. After reaching a certain level of experience and
competence, and mainly having acquired the discipline not to
use it unnecessarily, allowing goto's in certain cases seems
acceptable and reasonable. I use goto myself now and then;
but when I do it's a conscious decision made after considering
and comparing non-goto alternatives.

Good analogy, although I don't think of modifying function parameters as
being quite as harmful as using goto. I don't remember the last time I
wrote a C program with a goto anywhere, it's something which I wouldn't
rule out totally but I can usually avoid it without too much strain
(often by having multiple exit points to a function, which some people
regard as almost as bad).

Chris C
 
P

pete

CBFalconer said:
Because all this is illustrations of cases for the subject line,
not practical proposals. You snipped the whole raison d'etre.

It's not an example of fast code.
It's not an example of applying the rules of C
to do what strlen does.
 
C

Chris Torek

Good analogy, although I don't think of modifying function parameters as
being quite as harmful as using goto. ...

It is in some other, non-C languages:

SUBROUTINE FOO(X, I, LAST)
INTEGER I, LAST
REAL X(LAST)
IF (I .GT. LAST) GOTO 20
10 CONTINUE
COMPUT(X(I))
I = I + 1
GOTO 10
20 CONTINUE
RETURN
END

Here, this Fortran code has the obnoxious side effect of incrementing
the variable you call it with:

...
CALL FOO(ARR, I, 20)
C now I .EQ. 21

Perhaps some of the dogmatic "never modify a parameter" is left over
from old Fortran coders. :)
 
T

Tim Rentsch

CBFalconer said:
I've put myself in a peculiar position, for one who espouses Pascal
and the restrictions imposed by strong typing, etc. Here I am
arguing for the elimination of restrictions in C. In part it is
the minimalist in me - I don't want any extra variables declared,
and I don't want any extra restrictions forcing me to so declare.

Up to here I understand what you're saying.

I consider every extra thing that is needed to be known outside the
connected modules to be a connection. For a normal non-static
function there are three entities involved: The user, the
prototype, and the function. For minimal connectivity there should
be minimal restrictions on the user and the function. In general
we can consider the prototype to be the longest lived of all.

Maybe this makes sense.

For the rest of it you lose me. I'm not sure how some words
are being used, nor what you're meaning to say with them.

For the three entities: of course the developer has to
understand a function in order to write it or modify it; it
can't be any different whether there are lots of restrictions
or none at all.

As regards prototypes: having function parameters be const
needn't affect the function's prototype at all. The code
below is legal:

int foo( int );

...

int
foo( const int t ){
return t;
}

See 6.7.5.3 p15 (the parenthesized final sentence).
 
C

Chris Croughton

It is in some other, non-C languages:

SUBROUTINE FOO(X, I, LAST)
INTEGER I, LAST
REAL X(LAST)
IF (I .GT. LAST) GOTO 20
10 CONTINUE
COMPUT(X(I))
I = I + 1
GOTO 10
20 CONTINUE
RETURN
END

Here, this Fortran code has the obnoxious side effect of incrementing
the variable you call it with:

Oh, I see, you are using CONTINUE as a null statement just to be the
target of the GOTO. Confused me at first, I was looking for the DO...
...
CALL FOO(ARR, I, 20)
C now I .EQ. 21

Perhaps some of the dogmatic "never modify a parameter" is left over
from old Fortran coders. :)

I am an old FORTRAN IV coder <g>. Interesting that it's something I
never particularly carried over (although I wouldn't use I as a
parameter, it's far too useful as a loop variable). I think I was
relieved when I found variables passed by value, although that might
trip me up if I ever program Fortran...

Chris C
 
M

Mark

Chris Croughton said:
Actually, it will exhibit undefined behaviour since the function returns
size_t and %d expects an int...

Actually, it's very well defined on my implementation.
size_t = unsigned int
with value explicitly set to 1 the sign bit is irrelevant.

You've peaked my curiosity, on what implementations
(excluding the infamous DeathStation 9000) is a
size_t not defined as an 'unsigned int' ?
> Since we're being picky, and all...

We? Ah, I didn't realize there were two of you! :)

Regards,
Mark
 
R

Richard Tobin

Chris Croughton said:
Oh, I see, you are using CONTINUE as a null statement just to be the
target of the GOTO. Confused me at first, I was looking for the DO...

Um, CONTINUE with a DO is just a null statement to be the termination
of the DO. You only need it when the terminating statement would be
a GOTO.

-- Richard
 
D

Dik T. Winter

> SUBROUTINE FOO(X, I, LAST)
> INTEGER I, LAST
> REAL X(LAST)
> IF (I .GT. LAST) GOTO 20
> 10 CONTINUE
> COMPUT(X(I))
> I = I + 1
> GOTO 10
> 20 CONTINUE
> RETURN
> END
>
> Here, this Fortran code has the obnoxious side effect of incrementing
> the variable you call it with:

It has a much more obnoxious effect. If I <= LAST on entry it gives
an infinite loop and quite some UB. ;-).
 
C

Chris Croughton

Actually, it's very well defined on my implementation.
size_t = unsigned int
with value explicitly set to 1 the sign bit is irrelevant.

You've peaked my curiosity, on what implementations
(excluding the infamous DeathStation 9000) is a
size_t not defined as an 'unsigned int' ?

At least one x86 compiler which had 16 bit int but allowed objects
bigger than 64KB (Aztec? IAC? One of the expensive ones, anyway). The
same can easily apply to 64 bit machines (IIRC one of the DEC Alpha
compilers had size_t 64 bits and int 32 bits). Definitely doesn't need
a DS9000 series machine, the usual recommendation is to cast it to
unsigned long at least for printing (unsigned long long with a compiler
and library which support that)..
We? Ah, I didn't realize there were two of you! :)

I am large, I contain multitudes (generally attributed to Walt Whitman,
but I've heard that it have been said earlier).

Chris C
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,830
Latest member
ZADIva7383

Latest Threads

Top