By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,376 Members | 1,581 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,376 IT Pros & Developers. It's quick & easy.

Should function argument be changed in function body?

P: n/a
Hi All,

I was taught that argument valuse is not supposed to be changed in
function body. Say, below code is not good.
void foo1(int x)
{
x ++;
printf("x+1 = %d\n", x);
}
It should be "refactor-ed" to be
void foo2(int x)
{
int y = x;
y ++;
printf("x + 1 = %d\n", y);
}

Recently, I found one guy posted code like foo1 in one C lang forum. I
pointed out that it is not good code standard. Surprisingly, seems all
people criticise me as dogmatism. It is claimed that changing arugment
value will not affect caller code and it saves stack size. I understand
their point, but I DO remember it is commmon that argument is not
suppsoed to be changed.

Now I am confused. Is there anybody can give some explaination why it is
a code rule that argument should not be changed?
Thanks & Regards
Nov 15 '05 #1
Share this Question
Share on Google+
64 Replies


P: n/a
Morgan Cheng wrote:
.... snip ...
Now I am confused. Is there anybody can give some explaination
why it is a code rule that argument should not be changed?


The only reason not to modify arguments is that the initial value
is required later. Any such rule is pure foolishness. You should
think of arguments as externally initialized local variables (which
is precisely what they are). For example:

int putblanks(size_t n, FILE *f)
{
while (n--)
if (EOF == putc(' ', f)) return EOF;
return ' ';
}

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 15 '05 #2

P: n/a


Morgan Cheng wrote:
Hi All,

I was taught that argument valuse is not supposed to be changed in
function body. Say, below code is not good.
void foo1(int x)
{
x ++;
printf("x+1 = %d\n", x);
}
It should be "refactor-ed" to be
void foo2(int x)
{
int y = x;
y ++;
printf("x + 1 = %d\n", y);
}

Recently, I found one guy posted code like foo1 in one C lang forum. I
pointed out that it is not good code standard. Surprisingly, seems all
people criticise me as dogmatism. It is claimed that changing arugment
value will not affect caller code and it saves stack size. I understand
their point, but I DO remember it is commmon that argument is not
suppsoed to be changed.

Now I am confused. Is there anybody can give some explaination why it is
a code rule that argument should not be changed?
Thanks & Regards


Yeah,changing argument values is really not a good habit.I wanna try to
explain it using asm,though I just BEGIN to learn it.
Use gcc to change the code above into asm, and look for the
differences.You
will find function arguments are pushed into 'stack' and the return
value is in %eax register.If you change the argument in the 4(%esp),it
is bad of course.Er,just so so.
If I am not right,correct this at once! I just have a try! :-(

Nov 15 '05 #3

P: n/a
Morgan Cheng wrote:
Hi All,

I was taught that argument valuse is not supposed to be changed in
function body. Say, below code is not good.
void foo1(int x)
{
x ++;
printf("x+1 = %d\n", x);
}
It should be "refactor-ed" to be
void foo2(int x)
{
int y = x;
y ++;
printf("x + 1 = %d\n", y);
}

Recently, I found one guy posted code like foo1 in one C lang forum. I
pointed out that it is not good code standard. Surprisingly, seems all
people criticise me as dogmatism. It is claimed that changing arugment
value will not affect caller code and it saves stack size. I understand
their point, but I DO remember it is commmon that argument is not
suppsoed to be changed.

Now I am confused. Is there anybody can give some explaination why it is
a code rule that argument should not be changed?


As Chuck Falconer pointed out, the only pragmatical reason _not_ to
change an argument value is that you need it later on.
One _could_ probably argue also that an argument should not be "abused"
for another purpose, e.g. using an argument green_val to store the
result of a completely unrelated computation (instead of introducing
a temporary variable with an apt name, say wobble_factor).
These are the only reasons I can come up with right now.

Making your "rule" into a mandatory rule for a coding standard is indeed
unnecessary dogmatism bordering on sheer folly.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 15 '05 #4

P: n/a
Cong Wang wrote:

Morgan Cheng wrote:
Hi All,

I was taught that argument valuse is not supposed to be changed in
function body. Say, below code is not good.
void foo1(int x)
{
x ++;
printf("x+1 = %d\n", x);
}
It should be "refactor-ed" to be
void foo2(int x)
{
int y = x;
y ++;
printf("x + 1 = %d\n", y);
}

Recently, I found one guy posted code like foo1 in one C lang forum. I
pointed out that it is not good code standard. Surprisingly, seems all
people criticise me as dogmatism. It is claimed that changing arugment
value will not affect caller code and it saves stack size. I understand
their point, but I DO remember it is commmon that argument is not
suppsoed to be changed.

Now I am confused. Is there anybody can give some explaination why it is
a code rule that argument should not be changed?


Yeah,changing argument values is really not a good habit.I wanna try to
explain it using asm,though I just BEGIN to learn it.
Use gcc to change the code above into asm, and look for the
differences.You
will find function arguments are pushed into 'stack' and the return
value is in %eax register.If you change the argument in the 4(%esp),it
is bad of course.Er,just so so.
If I am not right,correct this at once! I just have a try! :-(


You are not right.
This is a pseudo-efficiency, pseudo-clarity argument.
C is not assembler, so this does not play a role. At all.
<OT>
Apart from that: Where do you think variables come from/are stored to?
Translating the C code into assembler may well lead to loading an often
used argument into a register, retrieving it only from this register,
nothing forces the compiler to "leave" the variable in the stack.
</OT>

Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Nov 15 '05 #5

P: n/a
CBFalconer wrote:

Morgan Cheng wrote:
... snip ...

Now I am confused. Is there anybody can give some explaination
why it is a code rule that argument should not be changed?


The only reason not to modify arguments is that the initial value
is required later.


I don't think that's a good reason.
If the specifcation were to suddenly change from the code example

void foo1(int x)
{
x ++;
printf("x+1 = %d\n", x);
}

to
int foo1(int x);
with the return value being the initial value of x,
I would do it this way:

int foo1(int x)
{
const int y = x;

x ++;
printf("x+1 = %d\n", x);
return y;
}

I think the code is easier to read
if the computations use the parameters.

char *str_cpy(char *s1, const char *s2)
{
char *const p1 = s1;

do {
*s1++ = *s2;
} while (*s2++ != '\0');
return p1;
}

If the intial value of a parameter is important,
it's easy to just pop in const qualified object.
Any such rule is pure foolishness. You should
think of arguments as externally initialized local variables (which
is precisely what they are).


--
pete
Nov 15 '05 #6

P: n/a
pete wrote:
CBFalconer wrote:
.... snip ...
The only reason not to modify arguments is that the initial value
is required later.


I don't think that's a good reason.
If the specifcation were to suddenly change from the code example

void foo1(int x)
{
x ++;
printf("x+1 = %d\n", x);
}

to
int foo1(int x);
with the return value being the initial value of x,
I would do it this way:

int foo1(int x)
{
const int y = x;

x ++;
printf("x+1 = %d\n", x);
return y;
}


I wouldn't. What has ++ got to do with anything? I would write:

int foo1(int x) {
printf("x+1 = %d\n", x+1);
return x;
}

easily read by non C programmers and which is also easily modified
to return void. I don't believe in returning the value of entry
parameters anyhow, because that leads to such ugly foulups as:

printf("%s %s\n", b, strcat(b, a));

You will never have this foulup using strlcat.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

Nov 15 '05 #7

P: n/a
CBFalconer wrote:
The only reason not to modify arguments is that the initial value
is required later. Any such rule is pure foolishness. You should
Well, I have some industry experience. All of the code standard requires
that arguments are not to be changed. Even in embedded system
development, this rule is still required. I believe this rule is good
for code maintenance.
think of arguments as externally initialized local variables (which
is precisely what they are). For example:

int putblanks(size_t n, FILE *f)
{
while (n--)
if (EOF == putc(' ', f)) return EOF;
return ' ';
}

Nov 15 '05 #8

P: n/a

Well, I have some industry experience. All of the code standard requires
that arguments are not to be changed. Even in embedded system
development, this rule is still required. I believe this rule is good
for code maintenance.


Well, I have some industry experience as well and have never come
across this in a coding standard.

Nov 15 '05 #9

P: n/a
Morgan Cheng wrote:
I was taught that
argument values are not supposed to be changed in function body.
Say, below code is not good.

void foo1(int x) {
++x;
printf("x+1 = %d\n", x);
}

should be "refactor-ed" to be

void foo2(int x) {
int y = x;
++y;
printf("x + 1 = %d\n", y);
}
This is *not* refactoring. You changed the API.
Recently, I found one guy posted code like foo1 in one C lang forum.
I pointed out that it is not good code standard.
Surprisingly, it seems that everybody criticised me as dogmatic.
It is claimed that changing arugment value will not affect caller code
and it saves stack size. I understand their point
but I *do* remember that it is commmon that
argument is not suppsoed to be changed.

Now I am confused. Is there anybody who can give some explaination,
"Why it is a code rule that argument should not be changed?"


There are several possible sources of confusion.
First, a function should *not* modify any of its *actual* arguments.
Instead of

void f(int* p) {
++(*p);
}

you should write

int f(const int* p) {
return *p + 1;
}

The example that you have provided passes by value
so it cannot modify its actual argument.
The *formal* argument is a copy of the *actual* argument.
If the *formal* argument should not be modified,
you should have written

void foo2(const int x) {
int y = x;
++y;
printf("x + 1 = %d\n", y);
}

Strictly speaking, it is up to the programmer
to decide whether [formal] arguments passed by value
are local constants or local variables.
Generally, you will *not* want to make a copy

void foo3(const HugeObjectType* p) {
// Use *p but don't modify it.
}

Your shop may enforce a rule
that generally forbids modifying formal arguments
to avoid accidently modifying actual arguments
(arguments passed by reference [through a pointer])
but objects must sometimes be modified *in-place*

HugeObjectType* foo4(HugeObjectType* p) {
// Modify *p
return p;
}

For example

char *strcpy(char *dest, const char *src);
Nov 15 '05 #10

P: n/a
In article <db**********@avnika.corp.mot.com>,
Morgan Cheng <mo***@nospam.nospam> wrote:

I was taught that argument value is not supposed to be changed in
function body.


How dare you question the rules that you have been taught!
--
7842++
Nov 15 '05 #11

P: n/a
>> Recently, I found one guy posted code like foo1 in one C lang forum.
I pointed out that it is not good code standard.
Surprisingly, it seems that everybody criticised me as dogmatic.
It is claimed that changing arugment value will not affect caller code
and it saves stack size. I understand their point
but I *do* remember that it is commmon that
argument is not suppsoed to be changed.

Now I am confused. Is there anybody who can give some explaination,
"Why it is a code rule that argument should not be changed?"

Generally I prefer not to change the formal arguments to a function,
because sooner or later I want the original value (even if it's in
a debugger only) for some reason. I don't consider it a "rule".
There are several possible sources of confusion.
First, a function should *not* modify any of its *actual* arguments.
I'll disagree strongly here, if what you mean is that you shouldn't
modify what a pointer passed in as an argument points at. How,
otherwise, would you handle something like the second argument of
strtol() or strtod()? Or for that matter, any function whose purpose
is to copy strings (strcpy(), strcat(), sprintf(), etc.)?

Obviously, any such argument should be clearly documented. Occasionally
a pointed-at value is used as both input AND output (e.g. it's a
pointer to where you left off in the parsing, and the new value is
where it left off after parsing the next token, used occasionally
in code intended to be a reentrant version of strtok() with a
necessarily modified argument list).
Instead of

void f(int* p) {
++(*p);
}

you should write

int f(const int* p) {
return *p + 1;
}


That's nice if the return value isn't being used for something else.
It is common for a function to need to return both a value and a
status of whether it worked or not. Sometimes this can be combined
into one (e.g. return NULL if it failed, pointer to something
otherwise), but there are objections to overloading the return value
like that also). Sometimes it can't (like if you want to return
an indicator of WHY it failed, and introducing more global variables
used like errno is also frowned on).

Gordon L. Burditt
Nov 15 '05 #12

P: n/a
Morgan Cheng wrote:

CBFalconer wrote:
The only reason not to modify arguments is that the initial value
is required later. Any such rule is pure foolishness. You should


Well, I have some industry experience. All of the code standard requires
that arguments are not to be changed. Even in embedded system
development, this rule is still required. I believe this rule is good
for code maintenance.

[...]

What industry, and whose standards? What is the rationale?

--
+-------------------------+--------------------+-----------------------------+
| Kenneth J. Brody | www.hvcomputer.com | |
| kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
Nov 15 '05 #13

P: n/a
Gordon Burditt wrote:
Recently, I found one guy posted code like foo1 in one C lang forum.
I pointed out that it is not good code standard.
Surprisingly, it seems that everybody criticised me as dogmatic.
It is claimed that changing arugment value will not affect caller code
and it saves stack size. I understand their point
but I *do* remember that it is commmon that
argument is not suppsoed to be changed.

Now I am confused. Is there anybody who can give some explaination,
"Why it is a code rule that argument should not be changed?"


Generally I prefer not to change the formal arguments to a function,
because sooner or later I want the original value
(even if it's in a debugger only) for some reason.
I don't consider it a "rule".
There are several possible sources of confusion.
First, a function should *not* modify any of its *actual* arguments.


I'll disagree strongly here, if what you mean is that
you shouldn't modify what a pointer passed in as an argument points at.
How, otherwise, would you handle something like
the second argument of strtol() or strtod()?
Or, for that matter, any function whose purpose is to copy strings
(strcpy(), strcat(), sprintf(), etc.)?

Obviously, any such argument should be clearly documented.
Occasionally, a pointed-at value is used as both input AND output
(e.g. it's a pointer to where you left off in the parsing
and the new value is where it left off after parsing the next token,
used occasionally in code intended to be a reentrant version of strtok()
with a necessarily modified argument list).
Instead of

void f(int* p) {
++(*p);
}

you should write

int f(const int* p) {
return *p + 1;
}

That's nice if the return value isn't being used for something else.
It is common for a function to need to return
both a value and a status of whether it worked or not.
Sometimes this can be combined into one
(e.g. return NULL if it failed, pointer to something otherwise)
but there are objections to overloading the return value like that also).
Sometimes it can't (like if you want to return an indicator of WHY it failed
and introducing more global variables used like errno is also frowned

on).

The preferred solution is to return both values in a struct as in

div_t div(int numerator, int denominator);
ldiv_t ldiv(long numerator, long denominator);
lldiv_t lldiv(long long numerator, long long denominator);

You should try to avoid passing a non const pointer to a function
unless the object must be modified *in-place*. Usually,
only container objects (arrays for example) are modified in-place --
strtol(), strtod(), strcpy(), strcat(), strtok(), etc.

C does not have a very good exception handling mechanism.
Using a function argument to return status is a hack.
Generally, you can't use the function in an expression
because you must check the status code first.
cat main.c #include <stdio.h>

typedef struct Pair {
int value;
int status;
} Pair;

inline static
Pair f(const int i) {
Pair p;
p.value = i + 13;
p.status = 0;
return p;
}

int main(int argc, char* argv[]) {
const
Pair p = f(42);
fprintf(stdout, "value = %d\tstatus = %d\n",
p.value, p.status);
return 0;
}
gcc -Wall -std=c99 -pedantic -O2 -o main main.c
./main

value = 55 status = 0

Nov 15 '05 #14

P: n/a
>>>There are several possible sources of confusion.
First, a function should *not* modify any of its *actual* arguments.
I'll disagree strongly here, if what you mean is that
you shouldn't modify what a pointer passed in as an argument points at.
How, otherwise, would you handle something like
the second argument of strtol() or strtod()?
Or, for that matter, any function whose purpose is to copy strings
(strcpy(), strcat(), sprintf(), etc.)?

Obviously, any such argument should be clearly documented.
Occasionally, a pointed-at value is used as both input AND output
(e.g. it's a pointer to where you left off in the parsing
and the new value is where it left off after parsing the next token,
used occasionally in code intended to be a reentrant version of strtok()
with a necessarily modified argument list).
Instead of

void f(int* p) {
++(*p);
}

you should write

int f(const int* p) {
return *p + 1;
}

That's nice if the return value isn't being used for something else.
It is common for a function to need to return
both a value and a status of whether it worked or not.
Sometimes this can be combined into one
(e.g. return NULL if it failed, pointer to something otherwise)
but there are objections to overloading the return value like that also).
Sometimes it can't (like if you want to return an indicator of WHY it failed
and introducing more global variables used like errno is also frowned

on).

The preferred solution is to return both values in a struct as in


If the values have some reasonable relationship to each other, I'll
agree with that. If it's a status glued onto something else, I
don't.

div_t div(int numerator, int denominator); But *NOT*:
struct status_and_quotient_t { int status,
long quotient} divv(long numerator, int denominator)
ldiv_t ldiv(long numerator, long denominator);
lldiv_t lldiv(long long numerator, long long denominator);

You should try to avoid passing a non const pointer to a function
unless the object must be modified *in-place*. Usually,
only container objects (arrays for example) are modified in-place --
strtol(), strtod(), strcpy(), strcat(), strtok(), etc.
What is the container object modified by strtod()? A char * is
modified, which points into an array which is NOT modified.
C does not have a very good exception handling mechanism.
Using a function argument to return status is a hack.
No, I want to use the return value to return status and
the function argument to return the results.
Generally, you can't use the function in an expression
because you must check the status code first.
Which is why I want to return the status and use the function
argument to return the results.
> cat main.c

#include <stdio.h>

typedef struct Pair {
int value;
int status;
} Pair;

inline static
Pair f(const int i) {
Pair p;
p.value = i + 13;
p.status = 0;
return p;
}

int main(int argc, char* argv[]) {
const
Pair p = f(42);
fprintf(stdout, "value = %d\tstatus = %d\n",
p.value, p.status);
return 0;
}
> gcc -Wall -std=c99 -pedantic -O2 -o main main.c
> ./main

value = 55 status = 0

Gordon L. Burditt
Nov 15 '05 #15

P: n/a
CBFalconer wrote:

I don't believe in returning the value of entry parameters anyhow,
because that leads to such ugly foulups as:

printf("%s %s\n", b, strcat(b, a));
Amusingly, this is the same as:

printf("%s %s\n", strcat(b, a), b);
You will never have this foulup using strlcat.


I don't see your point. If the intention was to display the
string before and after, then you will need 2 printf calls
(and strcat's one is more concise than strlcat's):

printf("%s ", b);
printf("%s\n", strcat(b, a));

Nov 15 '05 #16

P: n/a
On Tue, 19 Jul 2005 09:41:26 +0800, in comp.lang.c , Morgan Cheng
<mo***@nospam.nospam> wrote:
Hi All,

I was taught that argument valuse is not supposed to be changed in
function body.
Thats silly. If you need the original value elsewhere in the function,
then fine, but otherwise there's no reason not to do this.
void foo1(int x)
since x is a copy of the original object, altering it has no effect
outside foo1.
It should be "refactor-ed" to be
void foo2(int x)
{
int y = x;
this merely creates extra memory and uses up some cpu time.
Now I am confused. Is there anybody can give some explaination why it is
a code rule that argument should not be changed?


There's no such rule. It might be a company-specific coding standard,
I could understand a company insisting that arguments were not
altered, or all function names began with a letter designating the
module name, or contained exactly 32 characters, or used a form of
hungarian notation. But there's no necessity for it other than company
practice.
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>

----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Nov 15 '05 #17

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Morgan Cheng wrote:

... snip ...

Now I am confused. Is there anybody can give some explaination
why it is a code rule that argument should not be changed?


The only reason not to modify arguments is that the initial value
is required later. Any such rule is pure foolishness. [snip...]


With all due respect to the esteemed gentleman, I think this position
is on the wrong side of the fence. There are lots of reasons why it
can be useful to keep the original argument value available, eg,

showing the value with printf for some tracing
writing an assertion relating the function's output and input
viewing the value while debugging

All of these uses (not to mention some others) tend to show up later
in the development cycle as much as they do earlier when the code is
first written. It often isn't possible to anticipate on first
writing when the original value will subsequently be needed.

On the flip side, there is rarely a really compelling argument
that parameter variables should be modified:

1. Only one line of code is needed to declare and
initialize a variable in the function body proper;
2. Such lines are written quite easily/mechanically;
3. With a reasonable optimizing compiler, there is no
run-time cost or storage cost associated with doing
so.

To be pragmatic, a rule that says one should *never* modify a
parameter variable might be considered a bit dogmatic. But as a
guideline it almost certainly helps more than it hurts. To say that
another way, during code review the writer of the code should have the
burden of defending a function body that modifies a parameter. As a
reviewer, my questions would be something like these:

1. Is the function body small (under 10 lines, say)?
2. Is the code simple, and clearly and obviously correct?
3. Is the code highly unlikely to have to change in the
foreseeable future?

If the answers to any of the questions is NO, then it's almost
certainly better to follow the guideline and not modify any of
the parameter variables.
Nov 15 '05 #18

P: n/a
Tim Rentsch wrote:
.... snip ...
To be pragmatic, a rule that says one should *never* modify a
parameter variable might be considered a bit dogmatic. But as a
guideline it almost certainly helps more than it hurts. To say
that another way, during code review the writer of the code should
have the burden of defending a function body that modifies a
parameter. As a reviewer, my questions would be something like
these:

1. Is the function body small (under 10 lines, say)?
2. Is the code simple, and clearly and obviously correct?
3. Is the code highly unlikely to have to change in the
foreseeable future?

If the answers to any of the questions is NO, then it's almost
certainly better to follow the guideline and not modify any of
the parameter variables.


And I would say a better guide is to make the answers be YES. The
sort of usages you listed earlier in the snipped portion come under
the heading of "needed later" to me. While something like:

void foo(T param) {
T saveparam = param;

/* machinations */
}

only requires one extra line, it does require extra code.
Certainly that code may get optimized away, and very likely will if
saveparam is never used. Meanwhile it is just one more thing to
confuse a maintainer, and one more expansion of the source code.
It is also one more place for an optimizer to become confused.

All of this is basically just another style war. We have expressed
opinions, together with some justifications for such, and thus have
divided the world into non-cretins and cretins (where obviously
cretins disagree with me :-).

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 15 '05 #19

P: n/a
On Tue, 19 Jul 2005 12:39:27 -0700, E. Robert Tisdale wrote:

....
That's nice if the return value isn't being used for something else.
It is common for a function to need to return
both a value and a status of whether it worked or not.
Sometimes this can be combined into one
(e.g. return NULL if it failed, pointer to something otherwise)
but there are objections to overloading the return value like that also).
Sometimes it can't (like if you want to return an indicator of WHY it failed
and introducing more global variables used like errno is also frowned on).

The preferred solution is to return both values in a struct as in


That is a possible alternative but in practice is rarely the "preferred
option".
div_t div(int numerator, int denominator);
ldiv_t ldiv(long numerator, long denominator);
lldiv_t lldiv(long long numerator, long long denominator);
Yes, this is the classic example of this form, but you'll note that these
are just 3 variations of the same thing. There are few other
examples. It works OK here because there are just 2 integer values
involved but even with something as simple as this it can make the caller
code messy. From a good programming point of view it creates extra
coupling between the function and the caller because the caller has to
handle an extra type that isn't natural to the problem. Put it this way -
it is kludgy to involve a structure in a simple integer division operation.
You should try to avoid passing a non const pointer to a function unless
the object must be modified *in-place*.
Not really, this is a normal and correct technique in C. There is a
similar discussion about using references in C++ for this purpose, which
should be avoided in that language. Using pointers is one way of doing so. :-)
Usually, only container objects
(arrays for example) are modified in-place -- strtol(), strtod(),
strcpy(), strcat(), strtok(), etc.
True, along with structures. But changing for example the char ** argument
of strtod() would not be an improvement.
C does not have a very good exception handling mechanism. Using a
function argument to return status is a hack. Generally, you can't use
the function in an expression because you must check the status code
first.


It is probably more common for this reason for the status to be the return
value and to pass back data through a pointer argument. That is especially
natural when arrays and structures are involved but still works fine for
basic types and is consistent.

Lawrence

Nov 15 '05 #20

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
... snip ...

To be pragmatic, a rule that says one should *never* modify a
parameter variable might be considered a bit dogmatic. But as a
guideline it almost certainly helps more than it hurts. To say
that another way, during code review the writer of the code should
have the burden of defending a function body that modifies a
parameter. As a reviewer, my questions would be something like
these:

1. Is the function body small (under 10 lines, say)?
2. Is the code simple, and clearly and obviously correct?
3. Is the code highly unlikely to have to change in the
foreseeable future?

If the answers to any of the questions is NO, then it's almost
certainly better to follow the guideline and not modify any of
the parameter variables.


And I would say a better guide is to make the answers be YES.


Do you mean to say that every function body that you write is under 10
lines, simple and clearly/obviously correct (including to other
readers), and highly unlikely to have to change in the foreseeable
future?
[snip]

All of this is basically just another style war. We have expressed
opinions, together with some justifications for such, and thus have
divided the world into non-cretins and cretins (where obviously
cretins disagree with me :-).


In my experience style wars tend to happen when two parties simply
express little more than their own opinions; don't offer constructive
reasoning; refuse to engage in useful dialog; don't examine both the
costs and benefits on both sides; and don't try to identify when
certain practices make sense and when they don't.

I don't like style wars so I usually try to avoid people who exhibit
those behaviors, and also try not to exhibit them myself.
Nov 15 '05 #21

P: n/a
CBFalconer schrieb:
And I would say a better guide is to make the answers be YES. The
sort of usages you listed earlier in the snipped portion come under
the heading of "needed later" to me. While something like:

void foo(T param) {
T saveparam = param;

/* machinations */
}

only requires one extra line, it does require extra code.
Certainly that code may get optimized away, and very likely will if
saveparam is never used. Meanwhile it is just one more thing to
confuse a maintainer, and one more expansion of the source code.
It is also one more place for an optimizer to become confused.


Do all compilers optimise the unnecessary copying of function
parameters away?
Is a coding guideline discussed here that has got no measurable effect
on the generated machine instructions?

Regards,
Markus

Nov 15 '05 #22

P: n/a
Tim Rentsch wrote:
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
.... snip ...
1. Is the function body small (under 10 lines, say)?
2. Is the code simple, and clearly and obviously correct?
3. Is the code highly unlikely to have to change in the
foreseeable future?

If the answers to any of the questions is NO, then it's almost
certainly better to follow the guideline and not modify any of
the parameter variables.


And I would say a better guide is to make the answers be YES.


Do you mean to say that every function body that you write is
under 10 lines, simple and clearly/obviously correct (including
to other readers), and highly unlikely to have to change in the
foreseeable future?


I don't always succeed, but yes, those are objectives. :-) You
will have to judge the "including to others" portion yourself.
Feel free to root around in:

<http://cbfalconer.home.att.net/download/>

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 15 '05 #23

P: n/a
>CBFalconer schrieb:
... While something like:

void foo(T param) {
T saveparam = param;

/* machinations */
}

only requires one extra line, it does require extra code.
Certainly that code may get optimized away ...

In article <11**********************@g14g2000cwa.googlegroups .com>
<Ma************@web.de> wrote:Do all compilers optimise the unnecessary copying of function
parameters away?


Clearly the answer to this is "no", because there are some compilers
that do no optimization (either because they are not asked to, as
with gcc -O0, or because they simply do not do it).

One could instead ask: "do all good compilers optimize this away
when asked?" But this requires defining "good" :-) -- we could
simply claim that a "good" compiler *must* do so, and create a
tautology.

I have a simple technique that I prefer when dealing with functions
that, for whatever reason, need to take a parameter of the "wrong
type" (and then convert it to the right type) and/or save the
initial value of a parameter for some reason. I name the incoming
value "foo0", stealing the subscript-0 notation from mathematical
sequences:

X = <initial value>
0

X = <formula based on X[i-1]>
i

So I write:

void foo(T0 bar0) {
T bar = bar0;
... code ...
}

If T0 and T are the same type, this simply saves the original
value; if T0 and T are different types -- as is the case when a
callback function receives a "void *" parameter -- it also
adjusts the type and value of the parameter as needed:

/*
* We get called through a function pointer, and passed
* a pointer to our data structure as converted to "void *".
* We must return the value to be given to us on the next
* callback, or NULL to indicate that we should not be called
* again.
*/
void *some_callback(void *sp0) {
struct somestruct *sp = sp0;

sp->ncalls++;
do_something(sp->other);
sp->third = some_op(sp->fourth);
return sp->freeme ? (free(sp), NULL) : sp0;
}

for instance.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #24

P: n/a
"CBFalconer" <cb********@yahoo.com> wrote in message
news:42***************@yahoo.com...
Tim Rentsch wrote:
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
... snip ...
1. Is the function body small (under 10 lines, say)?
2. Is the code simple, and clearly and obviously correct?
3. Is the code highly unlikely to have to change in the
foreseeable future?

If the answers to any of the questions is NO, then it's almost
certainly better to follow the guideline and not modify any of
the parameter variables.

And I would say a better guide is to make the answers be YES.


Do you mean to say that every function body that you write is
under 10 lines, simple and clearly/obviously correct (including
to other readers), and highly unlikely to have to change in the
foreseeable future?


I don't always succeed, but yes, those are objectives. :-) You
will have to judge the "including to others" portion yourself.
Feel free to root around in:

<http://cbfalconer.home.att.net/download/>


uncmntc.zip - (picked at random)
1. Is the function body small (under 10 lines, say)? All with the exception of main.
2. Is the code simple, and clearly and obviously correct? Simple? Definitely. Clearly and obviously correct? No.
It was actually pretty obvious that it would not work properly :-)

As for style... PICK ONE!
I can understand why one puts the constant first in if statements
(in case you accidentally put = in place of == blah blah blah...
must be too hard to just look at the damn code when you type it!)
but you go 'both ways' on back to back lines! (74/75)
3. Is the code highly unlikely to have to change in the
foreseeable future?

That depends on whether or not you choose to fix your bugs...
What would your utility do if it encountered a line such as:
printf("What\\" /* embedded string */ "%s joke!\n", /* doh */ "a
/*#(K1N5");

Oh, it will strip something alright, but probably not what you'd expect ;)

Regards,
Mark

Nov 15 '05 #25

P: n/a
Mark wrote:
"CBFalconer" <cb********@yahoo.com> wrote in message
.... snip ...

I don't always succeed, but yes, those are objectives. :-) You
will have to judge the "including to others" portion yourself.
Feel free to root around in:

<http://cbfalconer.home.att.net/download/>


uncmntc.zip - (picked at random)


[doubtless because of its gargantuan size :-). Is that random?]
> 1. Is the function body small (under 10 lines, say)? All with the exception of main.
2. Is the code simple, and clearly and obviously correct? Simple? Definitely. Clearly and obviously correct? No.
It was actually pretty obvious that it would not work properly :-)


Wasn't to me at the time. :-(

As for style... PICK ONE!
I can understand why one puts the constant first in if statements
(in case you accidentally put = in place of == blah blah blah...
must be too hard to just look at the damn code when you type it!)
but you go 'both ways' on back to back lines! (74/75)
sad but true.
3. Is the code highly unlikely to have to change in the
> foreseeable future?

That depends on whether or not you choose to fix your bugs...
What would your utility do if it encountered a line such as:
printf("What\\" /* embedded string */ "%s joke!\n", /* doh */ "a
/*#(K1N5");

Oh, it will strip something alright, but probably not what you'd expect ;)


Well, you picked up that mishandling of escapes in echostring. At
least it was organized so that you could find that bug :-). I
don't think it is getting heavily used though, since I have had no
other bug reports in 3 or so years.

Where should I turn in my certificate of infallibility?

In all seriousness, I consider the rapidity with which you could
spot a fairly obscure bug as vindication of the style.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 15 '05 #26

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
[restoring snipped portion]

To be pragmatic, a rule that says one should *never* modify a
parameter variable might be considered a bit dogmatic. But as a
guideline it almost certainly helps more than it hurts. To say
that another way, during code review the writer of the code should
have the burden of defending a function body that modifies a
parameter. As a reviewer, my questions would be something like
these:

[end restoring snipped portion]

1. Is the function body small (under 10 lines, say)?
2. Is the code simple, and clearly and obviously correct?
3. Is the code highly unlikely to have to change in the
foreseeable future?

If the answers to any of the questions is NO, then it's almost
certainly better to follow the guideline and not modify any of
the parameter variables.

And I would say a better guide is to make the answers be YES.
Do you mean to say that every function body that you write is
under 10 lines, simple and clearly/obviously correct (including
to other readers), and highly unlikely to have to change in the
foreseeable future?


I don't always succeed, but yes, those are objectives. :-)


I don't know whether you missed reading the snipped paragraph or just
oversnipped. The questions are questions to be asked during code
review. They are asked about the code, not about the person who wrote
the code; effort or intention don't enter into the considerations.

You
will have to judge the "including to others" portion yourself.
Feel free to root around in:

<http://cbfalconer.home.att.net/download/>


I looked at id2id-20.zip, files hashlib.c and id2id.c. The median
function body length was about 12 lines in both cases, the average
function body length was a little higher, between 14 and 16 lines.
Although those numbers may be admirably low, they don't meet the
guideline mentioned.

To get back to the original topic: I don't believe the code I looked
at makes a good case that modifying function parameters should, as a
general rule, be thought of as good style. At the very least, it
should be immediately obvious which parameters are modified and which
are not. If a development team really wanted the freedom to modify a
function parameter on any function, then it would be good practice to
attach 'const' to any parameters that are not modified. There doesn't
seem to be much upside to allowing function parameters to be modified;
conversely, following a guideline that function parameters not be
modified has relatively low costs and fairly clear benefits. So even
though there may be specific exceptions, as a general development
practice discouraging modification of function parameters seems to
offer a good ROI.
Nov 15 '05 #27

P: n/a
Tim Rentsch writes:
There doesn't seem to be much upside to allowing function parameters
to be modified; conversely, following a guideline that function
parameters not be modified has relatively low costs and fairly
clear benefits.


Can you name some of those benefits? They're not clear to me.

(I agree that modifying function parameters is not something
you'd want to do every day, but sometimes it's convenient -- more
so that introducing a local variable to hold a modifiable copy --
and I don't understand the predilection in some circles for
mandating that parameters not be modified.)

Steve Summit
sc*@eskimo.com
Nov 15 '05 #28

P: n/a
>> There doesn't seem to be much upside to allowing function parameters
to be modified; conversely, following a guideline that function
parameters not be modified has relatively low costs and fairly
clear benefits.
Can you name some of those benefits? They're not clear to me.


(1) The original value is available in a debugger. It gets especially
confusing in stack traces, where the value printed for the call is
sometimes the original call value and is sometimes the modified
value, depending on compiler options.

I quit modifying function parameters after burning myself a couple
of times because of this (in code I originally wrote).

(2) The original value is sometimes wanted after original coding
for logging or debugging. I've managed to waste a lot of time when
I assumed that what was being printed was the original value, and
it wasn't.

(3) It can save hours of arguing with pedants who argue, among other
things, that goto is evil and printf("Go to the store and buy some
beer.\n"); is a use of goto in English.
(I agree that modifying function parameters is not something
you'd want to do every day, but sometimes it's convenient -- more
so that introducing a local variable to hold a modifiable copy --
and I don't understand the predilection in some circles for
mandating that parameters not be modified.)
I don't think this issue rises to the level of having to call
in the coding style police.
Steve Summit
sc*@eskimo.com


Gordon L. Burditt
Nov 15 '05 #29

P: n/a
Gordon Burditt wrote:
There doesn't seem to be much upside to allowing function parameters
to be modified; conversely, following a guideline that function
parameters not be modified has relatively low costs and fairly
clear benefits.
Can you name some of those benefits? They're not clear to me.


(1) The original value is available in a debugger. It gets especially
confusing in stack traces, where the value printed for the call is
sometimes the original call value and is sometimes the modified
value, depending on compiler options.
I quit modifying function parameters after burning myself a couple
of times because of this (in code I originally wrote).


I regularly debug with an IDE, and have never had any problem
inspecting the values of parameters, even if they've changed.
Once you've passed the opening { , those parameters are no
different to any other local variables.
(2) The original value is sometimes wanted after original coding
for logging or debugging. I've managed to waste a lot of time when
I assumed that what was being printed was the original value, and
it wasn't.
You can avoid this by declaring the parameters as const
(in the function definition -- you don't have to do it in
the prototype).

Also there's the argument that if you can't tell in a glance
whether the value has been modified, either your function is
too large or your variable name is too short (not that I
subscribe much to this argument, but it's out there).
(3) It can save hours of arguing with pedants who argue, among other
things, that goto is evil and printf("Go to the store and buy some
beer.\n"); is a use of goto in English.


Come on, don't you enjoy these discussions ;)

Nov 15 '05 #30

P: n/a
>>>> There doesn't seem to be much upside to allowing function parameters
to be modified; conversely, following a guideline that function
parameters not be modified has relatively low costs and fairly
clear benefits.

Can you name some of those benefits? They're not clear to me.
(1) The original value is available in a debugger. It gets especially
confusing in stack traces, where the value printed for the call is
sometimes the original call value and is sometimes the modified
value, depending on compiler options.
I quit modifying function parameters after burning myself a couple
of times because of this (in code I originally wrote).


I regularly debug with an IDE, and have never had any problem
inspecting the values of parameters, even if they've changed.


Well, when I look at a stack trace, I expect those values to
be the *ORIGINAL* values at the time of the call (since a lot
of messups happen because garbage was passed in to the function).
With parameters being modified, sometimes they are the original
values (compilers put parameter in a register and used it) and
sometimes they aren't (compiler left variable on the stack frame).
I don't know whether I ever did figure out a good way to determine
whether the stack trace was giving the original or the current value,
other than directly testing it by setting a breakpoint.

If I want the current value of the parameter, that isn't a problem.
But if I am, for example, traversing a linked list, it's likely to
have NULL or garbage when it screws up, and I'd like to know how I
got there.
Once you've passed the opening { , those parameters are no
different to any other local variables.
(2) The original value is sometimes wanted after original coding
for logging or debugging. I've managed to waste a lot of time when
I assumed that what was being printed was the original value, and
it wasn't.


You can avoid this by declaring the parameters as const
(in the function definition -- you don't have to do it in
the prototype).


In other words, DON'T modify parameters. const alone won't do
that (just prevent it from compiling if you try).
Also there's the argument that if you can't tell in a glance
whether the value has been modified, either your function is
too large or your variable name is too short (not that I
subscribe much to this argument, but it's out there).


Yes, I remember this argument, especially applied to a function to
print a blank form. It took one argument (the file descriptor to
put the form on, which varied from stdout (using a printing terminal)
to one gotten from popen("lpr", "w"). ). In theory, it could have
been written with one fputs() call with a very long quoted string,
but it was desirable to make the code look somewhat like the way
the form would print. So it had roughly one fputs() per line printed
on the form. It made no attempt to pre-fill-in blanks. The idea
here is that these forms were supposed to be filled out, then
entered, and after you entered one, it gave you another blank form.
This was before everyone had a laptop with wireless access to fill
these out online. Besides, you get fewer poll results if you are
trying to balance a laptop on the back of the person you're polling
while both of you are outside on the sidewalk.
(3) It can save hours of arguing with pedants who argue, among other
things, that goto is evil and printf("Go to the store and buy some
beer.\n"); is a use of goto in English.


Come on, don't you enjoy these discussions ;)


I can walk away from USENET. Pedants at work are harder to walk
away from, especially if one of them is your boss.

Gordon L. Burditt
Nov 15 '05 #31

P: n/a
[On reasons to leave the formal parameter variable unchanged in the
function body...]

In article <11*************@corp.supernews.com>
Gordon Burditt <go****@hammy.burditt.org> wrote:
(1) The original value is available in a debugger. It gets especially
confusing in stack traces, where the value printed for the call is
sometimes the original call value and is sometimes the modified
value, depending on compiler options.

I quit modifying function parameters after burning myself a couple
of times because of this (in code I originally wrote).
Not modifying the formal parameter will not save you from this
fate:

void f(int x0, int limit) {
int x;

for (x = x0; x < limit; x++)
do_something(x);
}

may compile to identical machine code as the same code with "x0"
changed to "x", and the now-redundant declaration for "x" removed.
(Indeed, I would expect this on machines that pass parameters in
registers.)

If you really need x0 saved, you would have to use it:

int f(int x0, int limit) {
int x;

for (x = x0; x < limit; x++)
do_something(x);
return x0;
}

but even then, I have had compilers decide that %i0 should be used
for the loop, and copied into %l1 at function entry, with the return
sequence being compiled as:

ret
restore %g0, %l1, %o0

In other words, the compiler cleverly rewrote my code as if it
read instead:

int f(int x, int limit) {
int x0 = x;

for (; x < limit; x++)
do_something(x);
return x0;
}
(2) The original value is sometimes wanted after original coding
for logging or debugging.
For this, I like the "x0" convention exhibited above (preferably
as the formal parameter name, rather than copied in the function
entry, but either one suffices).
(3) It can save hours of arguing with pedants who argue, among other
things, that goto is evil and printf("Go to the store and buy some
beer.\n"); is a use of goto in English.


Indeed. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #32

P: n/a
Tim Rentsch wrote:
.... snip ... general rule, be thought of as good style. At the very least, it
should be immediately obvious which parameters are modified and which
are not. If a development team really wanted the freedom to modify a
function parameter on any function, then it would be good practice to
attach 'const' to any parameters that are not modified. There doesn't
seem to be much upside to allowing function parameters to be modified;

.... snip ...

On the contrary, hanging extraneous 'const' on the parameters would
impose an extra anomalous connection between code modules. Without
it a future revisor can go ahead and confidently make the changes
he needs. The only real reason for const is to protect things
passed in via pointers, i.e. by reference in other languages.
Similarly a coder should strive to mark local functions as static.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 15 '05 #33

P: n/a
Gordon Burditt writes:
[I had written:]
Can you name some of those benefits? They're not clear to me.
(1) The original value is available in a debugger. It gets especially
confusing in stack traces...


Ah, that problem. Now that you mention it, I've been burned by
that, too.
(2) The original value is sometimes wanted after original coding
for logging or debugging.


Sure -- but that's a reason you might not want to do it under a
certain circumstance, not a reason for a blanket ban!
Nov 15 '05 #34

P: n/a
sc*@eskimo.com (Steve Summit) writes:
Tim Rentsch writes:
There doesn't seem to be much upside to allowing function parameters
to be modified; conversely, following a guideline that function
parameters not be modified has relatively low costs and fairly
clear benefits.
Can you name some of those benefits? They're not clear to me.


Sure. In a previous post I listed some specific cases where it's
useful to have the initial value available (quoting):

showing the value with printf for some tracing
writing an assertion relating the function's output and input
viewing the value while debugging

All of these uses (not to mention some others) tend to show up
later in the development cycle as much as they do earlier when
the code is first written. It often isn't possible to
anticipate on first writing when the original value will
subsequently be needed.

[End of quoting.]

There's also a different kind of benefit having to do with
comprehensibility. For example, in long functions, it's
usually better to initialize a loop variable right before
the loop: because the initialization is right there, it's
easy to see what it is, and know that the variable hasn't
been inadvertently set to the wrong thing. We can't do
that with a parameter -- it had to be initialized at the
beginning. Compare

t = n*3 + 7;

...

while( t-- ){
...
}

with

for( t = n*3 + 7; t--; ){
...
}

The second is better (I claim), because everything we
have to read for the loop is right there at the loop.
We don't always have this choice if parameters are used
in loops, because of how they are initialized.

Another example of a comprehensibility benefit is where
on the spectrum of imperative vs functional a piece of
code is. The more there is state that changes, and the
less there is state that doesn't change, generally the
harder we have to work to understand a given piece of
code. For example, compare

size_t
length_of_string( const char *s ){
size_t n = 0;

while( *s ) s++, n++;
return n;
}

with

size_t
length_of_string( const char *s ){
size_t n = 0;

while( s[n] ) n++;
return n;
}

I admit the difference between these functions isn't very big,
and in a code review I'd probably be ok with either one. But
the second one is a little easier to understand. I can see at a
glance that 'n' holds the index of the first null character in
the string 's'. Of course, I can see that in the first function
also, but there's a little more mental effort involved. You
see what I mean?

Summarizing the two examples above: a benefit of keeping
parameters unchanged is that it allows or encourages other
good development practices.

(I agree that modifying function parameters is not something
you'd want to do every day, but sometimes it's convenient -- more
so that introducing a local variable to hold a modifiable copy --
and I don't understand the predilection in some circles for
mandating that parameters not be modified.)


I expect we're not really that far apart on this. Let me offer
an analogy. Usually it's better for (non-const) variables to be
initialized subsequent to their declaration. Not always better,
not hugely better, but usually better. Every so often I am
tempted to "break the rule" and write initializing declarations.
When I give in to that temptation, probably 999 times out of
1000 everything works out fine. But every now and then I get
bitten by it. That's the thing: when I break the rule,
sometimes I get bitten; but when I follow the rule, I never do.

I suspect people who are strong advocates of never modifying
parameters do so largely for that reason - if one follows the
rule, one never gets bitten.

So if you want to make exceptions now and then, that's ok, just
be sure you bring your venom kit with you. :)

Nov 15 '05 #35

P: n/a
On 25 Jul 2005 12:34:17 -0700, Tim Rentsch
<tx*@alumnus.caltech.edu> wrote:
The second is better (I claim), because everything we
have to read for the loop is right there at the loop.
We don't always have this choice if parameters are used
in loops, because of how they are initialized.
I would generally agree with that, except in very small functions.
Another example of a comprehensibility benefit is where
on the spectrum of imperative vs functional a piece of
code is. The more there is state that changes, and the
less there is state that doesn't change, generally the
harder we have to work to understand a given piece of
code. For example, compare

size_t
length_of_string( const char *s ){
size_t n = 0;

while( *s ) s++, n++;
return n;
}
I would write it as:

size_t
length_of_string(const char *s)
{
size_t n = 0;
while (*s++) n++;
return n;
}

In general, I dislike the comma operator, it's too easily misread. In
cases where the result isn't needed, such as yours, I prefer to treat
them as statements and put them in a block.
with

size_t
length_of_string( const char *s ){
size_t n = 0;

while( s[n] ) n++;
return n;
} I admit the difference between these functions isn't very big,
and in a code review I'd probably be ok with either one. But
the second one is a little easier to understand. I can see at a
glance that 'n' holds the index of the first null character in
the string 's'.
It does, but I find that less obvious (what I want is the length of the
string, the position of the null character happens to be the same with C
strings but it is not a trivial equivalence).
Of course, I can see that in the first function
also, but there's a little more mental effort involved. You
see what I mean?
Actually, I feel the opposite.
Summarizing the two examples above: a benefit of keeping
parameters unchanged is that it allows or encourages other
good development practices.
Sometimes. It can also obscure things. For instance, take a function
similar to strcpy:

/**
* Copy a string, returning a pointer to the terminating null
* character of the destination.
*/

char *copy_string(char *dst, const char *src)
{
while (*src)
*dst++ = *src++;
return dst;
}

Doing that without modifying the parameters is more messy.
So if you want to make exceptions now and then, that's ok, just
be sure you bring your venom kit with you. :)


Indeed.

I do think that the general rules outlined several posts ago are good, a
function which modifies its parameters should be short and 'obviously'
correct, and should be trivial enough that it is unlikely to need
changing such that modifying the parameters is a problem. As in the
case of my copy_string() above, where the interface defines that only
the modified version of the destination pointer will ever be needed.

Chris C
Nov 15 '05 #36

P: n/a
Chris Croughton wrote:
Tim Rentsch <tx*@alumnus.caltech.edu> wrote:
The second is better (I claim), because everything we
have to read for the loop is right there at the loop.
We don't always have this choice if parameters are used
in loops, because of how they are initialized.


I would generally agree with that, except in very small functions.
Another example of a comprehensibility benefit is where
on the spectrum of imperative vs functional a piece of
code is. The more there is state that changes, and the
less there is state that doesn't change, generally the
harder we have to work to understand a given piece of
code. For example, compare

size_t
length_of_string( const char *s ){
size_t n = 0;

while( *s ) s++, n++;
return n;
}


I would write it as:

size_t
length_of_string(const char *s)
{
size_t n = 0;
while (*s++) n++;
return n;
}

In general, I dislike the comma operator, it's too easily misread.
In cases where the result isn't needed, such as yours, I prefer to
treat them as statements and put them in a block.


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)

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 15 '05 #37

P: n/a
CBFalconer wrote:
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)


ptr_diff is too small.
Why not just use strlen?

--
pete
Nov 15 '05 #38

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
... snip ...
general rule, be thought of as good style. At the very least, it
should be immediately obvious which parameters are modified and which
are not. If a development team really wanted the freedom to modify a
function parameter on any function, then it would be good practice to
attach 'const' to any parameters that are not modified. There doesn't
seem to be much upside to allowing function parameters to be modified;

... snip ...

On the contrary, hanging extraneous 'const' on the parameters would
impose an extra anomalous connection between code modules.


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.

Without
it a future revisor can go ahead and confidently make the changes
he needs. The only real reason for const is to protect things
passed in via pointers, i.e. by reference in other languages.
Similarly a coder should strive to mark local functions as static.


If one is in the habit of modifying parameter variables, the value of
'const' on a parameter is the same as that for other function-local
variables -- to guarantee that the variable is not modified after
getting its initial value. That in turn reduces cognitive load on
someone reading the code, knowing that the compiler would squawk
if the 'const' prohibition were violated.
Nov 15 '05 #39

P: n/a
Chris Croughton <ch***@keristor.net> writes:
On 25 Jul 2005 12:34:17 -0700, Tim Rentsch
<tx*@alumnus.caltech.edu> wrote:
[snip]
Another example of a comprehensibility benefit is where
on the spectrum of imperative vs functional a piece of
code is. The more there is state that changes, and the
less there is state that doesn't change, generally the
harder we have to work to understand a given piece of
code. For example, compare


[...snip my code, leaving his nearly identical version...]

size_t
length_of_string(const char *s)
{
size_t n = 0;
while (*s++) n++;
return n;
}

[snip]
with

size_t
length_of_string( const char *s ){
size_t n = 0;

while( s[n] ) n++;
return n;
}

I admit the difference between these functions isn't very big,
and in a code review I'd probably be ok with either one. But
the second one is a little easier to understand. I can see at a
glance that 'n' holds the index of the first null character in
the string 's'.


It does, but I find that less obvious (what I want is the length of the
string, the position of the null character happens to be the same with C
strings but it is not a trivial equivalence).
Of course, I can see that in the first function
also, but there's a little more mental effort involved. You
see what I mean?


Actually, I feel the opposite.


I know where you're coming from. What code seems "natural" to
people certainly varies from person to person. 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.

Summarizing the two examples above: a benefit of keeping
parameters unchanged is that it allows or encourages other
good development practices.


Sometimes. It can also obscure things. For instance, take a function
similar to strcpy:

/**
* Copy a string, returning a pointer to the terminating null
* character of the destination.
*/

char *copy_string(char *dst, const char *src)
{
while (*src)
*dst++ = *src++;
return dst;
}

Doing that without modifying the parameters is more messy.


(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.)

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.

So if you want to make exceptions now and then, that's ok, just
be sure you bring your venom kit with you. :)


Indeed.

I do think that the general rules outlined several posts ago are good, a
function which modifies its parameters should be short and 'obviously'
correct, and should be trivial enough that it is unlikely to need
changing such that modifying the parameters is a problem. As in the
case of my copy_string() above, where the interface defines that only
the modified version of the destination pointer will ever be needed.


In practice it sounds like our views are actually pretty
similar. I appreciate the comments.
Nov 15 '05 #40

P: n/a
pete wrote:
CBFalconer wrote:
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)


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.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 15 '05 #41

P: n/a
Tim Rentsch wrote:
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:

... snip ...
general rule, be thought of as good style. At the very least, it
should be immediately obvious which parameters are modified and which
are not. If a development team really wanted the freedom to modify a
function parameter on any function, then it would be good practice to
attach 'const' to any parameters that are not modified. There doesn't
seem to be much upside to allowing function parameters to be modified;

... snip ...

On the contrary, hanging extraneous 'const' on the parameters would
impose an extra anomalous connection between code modules.


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.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!

Nov 15 '05 #42

P: n/a
On Tue, 26 Jul 2005 02:15:50 GMT, CBFalconer
<cb********@yahoo.com> wrote:
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
Nov 15 '05 #43

P: n/a
On Tue, 26 Jul 2005 07:38:02 GMT, pete
<pf*****@mindspring.com> wrote:
CBFalconer wrote:
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)


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
Nov 15 '05 #44

P: n/a
On 26 Jul 2005 02:54:42 -0700, Tim Rentsch
<tx*@alumnus.caltech.edu> wrote:
Chris Croughton <ch***@keristor.net> writes:
Actually, I feel the opposite.
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.
Sometimes. It can also obscure things. For instance, take a function
similar to strcpy:

/**
* Copy a string, returning a pointer to the terminating null
* character of the destination.
*/

char *copy_string(char *dst, const char *src)
{
while (*src)
*dst++ = *src++;
return dst;
}

Doing that without modifying the parameters is more messy.


(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
Nov 15 '05 #45

P: n/a
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:

... snip ...
general rule, be thought of as good style. At the very least, it
should be immediately obvious which parameters are modified and which
are not. If a development team really wanted the freedom to modify a
function parameter on any function, then it would be good practice to
attach 'const' to any parameters that are not modified. There doesn't
seem to be much upside to allowing function parameters to be modified;
... snip ...

On the contrary, hanging extraneous 'const' on the parameters would
impose an extra anomalous connection between code modules.


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.


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.
Nov 15 '05 #46

P: n/a
Chris Croughton <ch***@keristor.net> writes:
On 26 Jul 2005 02:54:42 -0700, Tim Rentsch
<tx*@alumnus.caltech.edu> wrote:
[snip]
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>...


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.

Nov 15 '05 #47

P: n/a
"CBFalconer" <cb********@yahoo.com> wrote in message
news:42***************@yahoo.com...
<snip>
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
Nov 15 '05 #48

P: n/a
Mark wrote:

"CBFalconer" <cb********@yahoo.com> wrote in message
news:42***************@yahoo.com...
<snip>
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.


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.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
Nov 15 '05 #49

P: n/a
Tim Rentsch wrote:
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
CBFalconer <cb********@yahoo.com> writes:
Tim Rentsch wrote:
>
... snip ...
> general rule, be thought of as good style. At the very least, it
> should be immediately obvious which parameters are modified and which
> are not. If a development team really wanted the freedom to modify a
> function parameter on any function, then it would be good practice to
> attach 'const' to any parameters that are not modified. There doesn't
> seem to be much upside to allowing function parameters to be modified;
... snip ...

On the contrary, hanging extraneous 'const' on the parameters would
impose an extra anomalous connection between code modules.

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.


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.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson

Nov 15 '05 #50

64 Replies

This discussion thread is closed

Replies have been disabled for this discussion.