I have the following snippet of code that used to compile without warnings
before:
void *blech; /* yeah yeah, I know, I know. */
char *sstrdup(const char *s)
{
AllocCalled++;
(char *) blech = strdup(s);
if (blech == NULL) {
perror("sstringdup");
abort();
}
return (char *) blech;
}
When I try to compile this code the compiler bails out throwing an "invalid
lvalue in assignment" error in my face.
Removing the first (char *) is what's needed to get this section of code to
compile. It also compiled fine when I was on a 32 bit platform and with an
older (pre 4.0) GCC compiler.
I seek to understand why I get this error. While I've read to never cast
return values, I don't see why that would give an error here seeing how the
man page for strdup says a character pointer is returned.
--
One in 10 Europeans is allegedly conceived in an Ikea bed;
Two in 10 Europeans are allegedly conceived on the kitchen table.
--
comp.lang.c.moderated - moderation address: cl...@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line. Sorry.
> Hi,
>
> I have the following snippet of code that used to compile without warnings
> before:
>
> void *blech; /* yeah yeah, I know, I know. */
>
> char *sstrdup(const char *s)
> {
> AllocCalled++;
> (char *) blech = strdup(s);
First, no cast is required at all on the line above, assuming that
there is a prototype for the (non-standard) function strdup() in
scope. If the compiler knows (via a prototype or declaration) that
strdup() returns a pointer to char (as all the versions of this
popular non-standard function that I have ever seen do), it will
convert the char pointer to a void pointer automatically, no cast
required.
If there is no prototype or declaration for strdup() in scope, the
compiler is forced to assume that it returns an int. Now you can't
assign an int, except for the compile-time constant value of 0, to any
pointer without a cast. But if you don't have a prototype in scope
and the function returns something other than an int, you have a
serious defect in your code, with or without a cast.
It might just happen to seem to work correctly on common 32-bit
platforms, but it is almost guaranteed to break spectacularly if you
ever compile and run it on 64 bit Windows or Linux.
> if (blech == NULL) {
> perror("sstringdup");
> abort();
> }
>
> return (char *) blech;
This cast is absolutely not needed, since the function is defined to
return a pointer to char, the compiler will convert the void pointer
to a char pointer automatically.
> }
>
>
> When I try to compile this code the compiler bails out throwing an "invalid
> lvalue in assignment" error in my face.
>
> Removing the first (char *) is what's needed to get this section of code to
> compile. It also compiled fine when I was on a 32 bit platform and with an
> older (pre 4.0) GCC compiler.
It is possible that you tripped over one of the "bad" old gcc
extensions that has been cleaned out of newer versions. Or perhaps
your memory is failing and you wrote the code slightly differently now
than you did then.
> I seek to understand why I get this error. While I've read to never cast
> return values, I don't see why that would give an error here seeing how the
> man page for strdup says a character pointer is returned.
What you wrote does not cast the return value, that would be:
blech = (char *)strdup("whatever");
What you wrote casts the address in blech to a pointer to char in what
used to be called an rvalue. An rvalue has no location in memory and
nothing can be assigned to it. You put the cast in the wrong place.
By the way, your post implies that you are no longer working on a
32-bit platform, so I strongly suggest that you have a prototype for
strdup() in place.
> --
> One in 10 Europeans is allegedly conceived in an Ikea bed;
> Two in 10 Europeans are allegedly conceived on the kitchen table.
Remind me never to eat in your kitchen...
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
> (char *) blech = strdup(s);
This cast is not standard C. GCC 3.3 had extensions for
"Generalized Lvalues":
# Compound expressions, conditional expressions and casts are allowed as
# lvalues provided their operands are lvalues. This means that you can
# take their addresses or store values into them.
#
# All these extensions are deprecated.
Then, in the release notes of GCC 4.0.0:
# * The cast-as-lvalue, conditional-expression-as-lvalue and
# compound-expression-as-lvalue extensions, which were
# deprecated in 3.3.4 and 3.4, have been removed.
Remco Rijnders wrote:
[...]
> (char *) blech = strdup(s);
[...]
> When I try to compile this code the compiler bails out throwing an
> "invalid lvalue in assignment" error in my face.
Assignment to cast lvalues is a gcc extension that only exists in versions
of gcc prior to 4.0:
http://gcc.gnu.org/onlinedocs/gcc-3.4.5/gcc/Lvalues.html#Lvalues
However, the extension is deprecated and has been removed from the 4.0
series. (Does anyone know why? Does C99 provide equivalent functionality?)
Try:
blech = (void*) strdup(s);
...instead.
- --
+- David Given --McQ-+ "There is // One art // No more // No less // To
| d...@cowlark.com | do // All things // With art // Lessness." --- Piet
| (d...@tao-group.com) | Hein
+- www.cowlark.com --+
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
iD8DBQFDw5/pf9E0noFvlzgRAnqgAKCNTW4rhKCskPek1oP7HJ4PML5DywCgjJWw
lyjNRu0H9MaLClkfGmGcR1I=
=8a0+
-----END PGP SIGNATURE-----
> void *blech; /* yeah yeah, I know, I know. */
> char *sstrdup(const char *s)
> {
> AllocCalled++;
> (char *) blech = strdup(s);
Bad idea. Basically, all explicit casts between pointer types are bad
ideas. That's because almost all the cases where a pointer cast is
safe are already implicitly handled by the language, so there's no point
in spelling them out.
And you should never cast the left-hand side of an assignment.
> I seek to understand why I get this error. While I've read to never cast
> return values, I don't see why that would give an error here seeing how the
> man page for strdup says a character pointer is returned.
You're not casting the return value of strdup() here, your trying to
assign it to a copy of blech which you cast to a different pointer
type.
--
Hans-Bernhard Broeker (bro...@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Remco Rijnders <re...@webconquest.com> writes:
> I have the following snippet of code that used to compile without warnings
> before:
>
> void *blech; /* yeah yeah, I know, I know. */
>
> char *sstrdup(const char *s)
> {
> (char *) blech = strdup(s);
> return (char *) blech;
> }
> When I try to compile this code the compiler bails out throwing an "invalid
> lvalue in assignment" error in my face.
Yes. As is plain from the example, you are trying to assign a
"char *" to a "void *" which are not the same type. You are casting
the lvalue, which is wrong. Write
blech = (void *) strdup(s);
so that you cast the rvalue to the type of the lvalue.
You aren't alone here. GCC only started enforcing this with GCC 4.0,
and this caused a lot of work with many packages. Luckily the fix is
trivial.
Regards,
Roger
--
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
> I have the following snippet of code that used to compile without warnings
> before:
>
> void *blech; /* yeah yeah, I know, I know. */
>
> char *sstrdup(const char *s)
> {
> (char *) blech = strdup(s);
> return (char *) blech;
> }
> When I try to compile this code the compiler bails out throwing an "invalid
> lvalue in assignment" error in my face.
Yes. As is plain from the example, you are trying to assign a
"char *" to a "void *" which are not the same type. You are casting
the lvalue, which is wrong. Write
blech = (void *) strdup(s);
so that you cast the rvalue to the type of the lvalue.
You aren't alone here. GCC only started enforcing this with GCC 4.0,
and this caused a lot of work with many packages. Luckily the fix is
trivial.
Regards,
Roger
--
Roger Leigh
Printing on GNU/Linux? http://gimp-print.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
You can't use a cast expression as an lvalue, because it isn't one. You
can safely assign an expression of any pointer type into a
ponter-to-void without a cast. Any compiler that says otherwise is
wrong, and you can tell it so from me.
> void *blech; /* yeah yeah, I know, I know. */
> (char *) blech = strdup(s);
> Removing the first (char *) is what's needed to get this section of code to
> compile. It also compiled fine when I was on a 32 bit platform and with an
> older (pre 4.0) GCC compiler.
> I seek to understand why I get this error.
I'm sure I saw it in the manual somewhere.
try under extensions, lvalues.
> While I've read to never cast return values,
the above code is not.
>I don't see why that would give an error here seeing how the
> man page for strdup says a character pointer is returned.
Bye.
Jasen
> When I try to compile this code the compiler bails out throwing an
> "invalid lvalue in assignment" error in my face.
Right so. The cast is treated as the creation of an anonymous, temporary
object of type 'char*', and you are now assigning to this temporary. If
you cast, you should cast the value at the right side of the assignment.
> I seek to understand why I get this error. While I've read to never cast
> return values, I don't see why that would give an error here seeing how
> the man page for strdup says a character pointer is returned.
You're not casting the returnvalue but the lvalue on the other side of the
assignment.
Anyhow:
- Use the right pointer types, that way no type conversions are necessary.
- Don't cast. C already implicitly converts most types. If this gives you
errors or warnings, probably your design is wrong.
- Your use of a global is plain silly, what's that supposed to do?
Uli
>I have the following snippet of code that used to compile without warnings
>before:
you were using an extension of some compiler, which now appears to be gone.
it was a horrible mistake at the outset, good thing it was removed.
>void *blech; /* yeah yeah, I know, I know. */
>
>char *sstrdup(const char *s)
> (char *) blech = strdup(s);
there was no reason for this cast, the compiler already knows (if and) how
to convert between char * and void *.
> return (char *) blech;
fyi, there was no reason for this cast either.
>When I try to compile this code the compiler bails out throwing an "invalid
>lvalue in assignment" error in my face.
>I seek to understand why I get this error.
the result of a cast is not a modifiable lvalue, which is needed for an
assignment to succeed.
--
a signature
> When I try to compile this code the compiler bails out throwing an "invalid
> lvalue in assignment" error in my face.
This is because of the typecast.
> Removing the first (char *) is what's needed to get this section of code to
> compile. It also compiled fine when I was on a 32 bit platform and with an
> older (pre 4.0) GCC compiler.
foo.c:7: warning: use of cast expressions as lvalues is deprecated
You don't need to typecast the left value explicitly, it will be done
automatically.
[code]
#include <stdio.h>
#include <string.h>
char *bla(const char *s)
{
void *foo;
foo = strdup(s);
if (!foo) {
perror("bla");
return NULL;
}
return (char *) foo;
}
int main(int argc, char **argv)
{
printf("bla(): %s\n", bla("Hallo"));
return 0;
}
[/code]
This works. Without typecasting foo when assigning from strdup().
But it contains a memory leak, so do not use it like that.
HTH, Hannes
> void *blech; /* yeah yeah, I know, I know. */
> (char *) blech = strdup(s);
> When I try to compile this code the compiler bails out throwing an "invalid
> lvalue in assignment" error in my face.
>
As it should. In standard C the result of a cast is an rvalue and
cannot be assigned to. Treating it as an lvalue is a GNU extension.
> Removing the first (char *) is what's needed to get this section of code to
> compile. It also compiled fine when I was on a 32 bit platform and with an
> older (pre 4.0) GCC compiler.
>
Then you weren't using -ansi or equivalent e.g. -std=c89 .
> I seek to understand why I get this error. While I've read to never cast
> return values, I don't see why that would give an error here seeing how the
> man page for strdup says a character pointer is returned.
>
The problem is not with the return type of strdup().
- David.Thompson1 at worldnet.att.net
blech = (void *) strdup(s);
I believe the error is because you have cast blech to a char * and done
nothing with it.
No you should not. In C pointers are implicitly converted to void* so
you don't need the cast and it's presence may prevent an otherwise
required diagnostic if you don't have a prototype for the non-standard
strdup function in scope.
blech = strdup(s);
> I believe the error is because you have cast blech to a char * and done
> nothing with it.
No, it is because the OP has cast it and tried to assign to the cast value.
--
Flash Gordon
Living in interesting times.
Although my email address says spam, it is real and I read it.
Probably because it was confusing and not particularly useful. For
example, given
int n;
(double)n = 1.5;
the cast causes a conversion from double to int, not from int to double.
> Does C99 provide equivalent functionality?)
Certainly, and so does C90.
>
> Try:
>
> blech = (void*) strdup(s);
>
> ...instead.
That's exactly the equivalent functionality you're looking for. And
in this case, since a char* can be implicitly converted to a void*,
the cast is unnecessary:
blech = strdup(s);
That's assuming that strdup() returns char*. There's no standard C
function by that name, but there is such a function in POSIX.
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.