I am currently learning "pointers by following the book "The C Programming Language" by Brian and Dennis.
I failed to compile:
#include <stdio.h>
void _strcpy(char *s, char *t)
{
while(*s = *t )
;
}
And the error messages are:
warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
while(*s = *t )
~~~~~^~~~~~
55.c:5:16: note: place parentheses around the assignment to silence this warning
while(*s = *t )
^
( )
55.c:5:16: note: use '==' to turn this assignment into an equality comparison
while(*s = *t )
^
==
1 warning generated.
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
After trying to figure out what causes the errors, I think it might be the "out-of-bounds".
So, I tried this to test my assumption:
int main(void)
{
char *t = "now is the time";
char *s, *string = s;
while(*s = *t );
printf("%s", string);
}
Well, it still gave me the same error message above :(
Would it be the problem of the compiler?
I was using :
gcc -o [filename] [filename.c]
Could you help me out?
Thank you and have a lovely day!
CodePudding user response:
This is not an error but a warning.
Such a warning is meant to catch logical errors like this:
int found=0;
while (found=0) {
// do something
if (abc) {
found = 1;
}
}
Where an assignment was used when an equality comparison should have been used.
In your case, the assignment is intentional. So you can do as the warning suggests and put an extra set of parenthesis around the assignment to let the compiler know your intent.
while ((*s = *t ))
CodePudding user response:
Regarding assignment inside conditions:
K&R was written in the 1970s and therefore follows 1970s (complete lack of) best practices. This way to implement strcpy
from K&R actually became idiomatic C, even though it was later recognized as problematic for various reasons.
In the 1980s, programmers started to realize that using assignment inside if
or loop conditions was bad practice. Partially because it introduced a side effect in the middle of a control statement, partially because programmers had a tendency to mix up =
and ==
(especially Pascal programmers at the time, since Pascal uses :=
and =
).
To counter this, some confused 1980s movement emerged, propagating the use of "the Yoda conditions", which is about programming with "backwards grammar" like the fictional Yoda character. That is if(0 == x)
rather than if(x == 0)
.
However, this doesn't fix the more serious program design problem of mixing a control statement with one or several side effects. Also, people started to realize that compilers could easily warn against if(x = 0)
. So Turbo C from 1989 started to warn for "possible incorrect assignment", which was the end of the Yoda conditions.
All modern compilers have this warning too, but nowadays provide a "de facto standard" way to avoid the warning, namely to use double parenthesis: if((x = 0))
. This means "I actually meant to do assignment here on purpose". So the quick & dirty fix to your problem is to change the code into:
while ((*s = *t ))
Other issues:
Avoid identifiers starting with a leading underscore since those are reserved for the standard library implementation.
Combining the
Alternatives:
You could rewrite the code as (somewhat more readable)
void another_strcpy (char* s, char* t)
{
for(*s = *t; *s != '\0'; s , t )
{}
}
or perhaps as (very readable)
void another_strcpy (char* s, char* t)
{
*s = *t;
while(*s != '\0')
{
s ;
t ;
*s = *t;
}
}
Although as far as performance is concerned, all of these implementations (including the K&R one) are naive. Efficient copy algorithms, as seen inside production-quality standard libs, works on aligned chunks of data.
Also, ideally use const correctness and pointer aliasing optimizations:
void another_strcpy (char* restrict s, const char* restrict t)