Returning a pointer to a constant string

  • Thread starter =?iso-8859-1?q?Santiago_Urue=F1a?=
  • Start date
?

=?iso-8859-1?q?Santiago_Urue=F1a?=

Hi,

I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:

warning: assignment from incompatible pointer type

This is the code:


const char msg[] = "Test message";

const char *message(void) {
return msg;
}

int main(void){
const char * str;

str = (const char *)message;
str = (char *)message;
str = message; /* GCC warning! */

str = (const char *)msg;
str = (char *)msg;
str = msg;

return 0;
}

Oddly, GCC only gives the warning if no cast is used, but it doesn't
complain if the cast discards the const qualifier. Is this behavior
OK? I'm using GCC 4.1.2. Thanks!

Best regards,

Santi
 
W

Walter Roberson

=?iso-8859-1?q?Santiago_Urue=F1a?= said:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:
warning: assignment from incompatible pointer type
This is the code:
const char msg[] = "Test message";
const char *message(void) {
return msg;
}

Pay close attention to the placement of the const qualifiers.

const char msg[] says that msg[someindex] will be a const char

const char *message(void)

says that message will return a pointer to a char and that the
pointer is constant. (I think. I'm not -positive-. I haven't had
much occasion to use const.)
 
J

JimS

Hi,

I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:

warning: assignment from incompatible pointer type

This is the code:


const char msg[] = "Test message";

const char *message(void) {
return msg;
}

int main(void){
const char * str;

str = (const char *)message;
str = (char *)message;
str = message; /* GCC warning! */

message is a pointer to a function returning const char *. The
previous two casts are covering up a gratuitous mistake!

Jim
 
?

=?iso-8859-1?q?Santiago_Urue=F1a?=

str = (const char *)message;
message is a pointer to a function returning const char *. The
previous two casts are covering up a gratuitous mistake!
You are right! Silly me.

Anyway, the compiler doesn't give any warning even if the qualifier is
discarded by the cast:

str = (const char *)message();
str = (char *)message(); /* No warning! */
str = message();

Is this OK?

Thanks again.

Santi
 
?

=?iso-8859-1?q?Santiago_Urue=F1a?=

Anyway, the compiler doesn't give any warning even if the qualifier is
discarded by the cast:

str = (const char *)message();
str = (char *)message(); /* No warning! */
str = message();

Is this OK?
After thinking a little more about this, I think I have the answer:
the compiler shouldn't give a warning because a pointer to a non-const
object is being assigned to a pointer to a const object, and this is
totally OK because (anyway you cannot modify the object via the 'str'
pointer).

Thanks
 
K

Keith Thompson

Santiago Urueña said:
You are right! Silly me.

Anyway, the compiler doesn't give any warning even if the qualifier is
discarded by the cast:

str = (const char *)message();
str = (char *)message(); /* No warning! */
str = message();

Is this OK?

Please leave attribution lines in place for quoted text (i.e., lines
follow the conversation, and it's just polite to credit people for
their words.

A cast specifies a type conversion, but what it *really* does is tell
the compiler "I know exactly what I'm doing, don't bother me with
warnings". Because of that property, almost all casts should be
viewed with suspicion. Adding a cast for the sole purpose of
silencing a compiler warning is almost always a mistake; the correct
solution is usually to fix the code so the cast isn't required, either
by arranging for things to be of the desired type in the first place
or by using types that are converted implicitly.

One of the few cases where a cast is necessary is for some arguments
to variadic functions like printf(). For non-variadic functions, the
compiler knows the required type and is able to generate an implicit
conversion if necessary. For a variadic function, the compiler
doesn't necessarily have this information, so you have to give it some
help.
 
C

CBFalconer

Santiago said:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:

warning: assignment from incompatible pointer type

This is the code:

const char msg[] = "Test message";

const char *message(void) {
return msg;
}

msg is an array. &msg is a pointer to msg.
 
M

Martin Ambuhl

Santiago said:
Hi,

I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:

warning: assignment from incompatible pointer type

This is the code:


const char msg[] = "Test message";

const char *message(void) {
return msg;
}

int main(void){
const char * str;

str = (const char *)message;
str = (char *)message;
str = message; /* GCC warning! */

str = (const char *)msg;
str = (char *)msg;
str = msg;

return 0;
}

const char msg[] = "Test message";
/* msg (above) is a character array, but message is a function */
const char *message(void)
{
return msg;
}

int main(void)
{
const char *str;
str = message(); /* notice parenthesis; message is not a
pointer-to-char but a function
returning a (const) pointer-to-char */
str = msg;
return 0;
}
 
A

anders

Hmm as i see it
one type is a char [] and one is char *
that way
str = (char *)message();
works.
// Anders


Santiago said:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:
warning: assignment from incompatible pointer type
This is the code:
const char msg[] = "Test message";
const char *message(void) {
return msg;
}

msg is an array. &msg is a pointer to msg.
 
C

Charlie Gordon

Walter Roberson said:
=?iso-8859-1?q?Santiago_Urue=F1a?= said:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:
warning: assignment from incompatible pointer type
This is the code:
const char msg[] = "Test message";
const char *message(void) {
return msg;
}

Pay close attention to the placement of the const qualifiers.

const char msg[] says that msg[someindex] will be a const char

correct. It could also be written char const msg[].
const char *message(void)

says that message will return a pointer to a char and that the
pointer is constant.

No, such a pointer would be defined as char * const p; and it makes no sense
as a return value for a function.
(I think. I'm not -positive-. I haven't had much occasion to use const.)

It shows!
Please don't post misleading answers on subjects you know you don't master.
 
C

Charlie Gordon

Santiago Urueña said:
Hi,

I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:

warning: assignment from incompatible pointer type

This is the code:


const char msg[] = "Test message";

const char *message(void) {
return msg;
}

int main(void){
const char * str;

str = (const char *)message;
str = (char *)message;
str = message; /* GCC warning! */

str = (const char *)msg;
str = (char *)msg;
str = msg;

return 0;
}

Oddly, GCC only gives the warning if no cast is used, but it doesn't
complain if the cast discards the const qualifier. Is this behavior
OK? I'm using GCC 4.1.2. Thanks!

Well well, gcc gives you a warning and you don't read it.
"assignment from incompatible pointer type" is not about the const
qualifier being discarded... after all str is a const char *, no const
qualifier is discard by these assignments, as the rest of the code shows.

The problem is much worse, and a good example of why casts must be avoided.
You are attempting to store a pointer to the function 'message', not the
result of an invocation because you missed the ().

str = message; is correctly diagnosed as an assignment from incompatible
pointer types.

By casting message to (char*) or (const char*), you are effectively telling
the compiler to shut up because you presumably know what you are doing (for
instance, you are trying to disassemble the function and you know the
respective representations of function pointers and char pointers are
compatible on your target). gcc respects that and does not complain.

But you are wrong. Your code invokes undefined behaviour.

Consequently: do not use casts. Turn extra gcc warnings on so it complains
about suspicious casts and a flew of other things.
 
C

Charlie Gordon

CBFalconer said:
Santiago said:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:

warning: assignment from incompatible pointer type

This is the code:

const char msg[] = "Test message";

const char *message(void) {
return msg;
}

msg is an array. &msg is a pointer to msg.

But message returns a pointer to char, correctly constructed by 'return
msg;' or 'return &msg[0];'.

Returning &msg here would be abusing the rules.
 
?

=?iso-8859-1?q?Santiago_Urue=F1a?=

"Santiago Urueña" <[email protected]> a écrit dans le message de (e-mail address removed)...


I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:
warning: assignment from incompatible pointer type
This is the code:
const char msg[] = "Test message";
const char *message(void) {
return msg;
}
int main(void){
const char * str;
str = (const char *)message;
str = (char *)message;
str = message; /* GCC warning! */
str = (const char *)msg;
str = (char *)msg;
str = msg;
return 0;
}
Oddly, GCC only gives the warning if no cast is used, but it doesn't
complain if the cast discards the const qualifier. Is this behavior
OK? I'm using GCC 4.1.2. Thanks!

Well well, gcc gives you a warning and you don't read it.
"assignment from incompatible pointer type" is not about the const
qualifier being discarded... after all str is a const char *, no const
qualifier is discard by these assignments, as the rest of the code shows.

The problem is much worse, and a good example of why casts must be avoided.
You are attempting to store a pointer to the function 'message', not the
result of an invocation because you missed the ().

str = message; is correctly diagnosed as an assignment from incompatible
pointer types.

By casting message to (char*) or (const char*), you are effectively telling
the compiler to shut up because you presumably know what you are doing (for
instance, you are trying to disassemble the function and you know the
respective representations of function pointers and char pointers are
compatible on your target). gcc respects that and does not complain.

But you are wrong. Your code invokes undefined behaviour.

Consequently: do not use casts. Turn extra gcc warnings on so it complains
about suspicious casts and a flew of other things.
Thank you very much for all your responses. Of course I see the
problem now, it seems I was too asleep for not seeing that silly
mistake.

I always use -Wall and -Wextra until all warnings are corrected. I'm
of those persons that believe that the compiler usually knows much
better, I don't really know why in this case the message seemed to me
a possible compiler bug.

Keith, Thanks for the suggestion about variadic functions, it's always
good to know tips like that. I don't usually use casts neither,
specially from now on... :)

Best regards,
 
?

=?iso-8859-1?q?Santiago_Urue=F1a?=

Santiago said:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:
warning: assignment from incompatible pointer type
This is the code:
const char msg[] = "Test message";
const char *message(void) {
return msg;
}

msg is an array. &msg is a pointer to msg.
I'm not a language lawyer, but the & operator returns the _address_ of
an object, not the pointer. But in this case 'msg' is directly the
address of the array.

I declared 'msg' as 'const char msg[] = "...";' and not as 'const char
*const msg = "...";' because in this case there is no need to reserve
memory for a pointer to the string, but just to the string itself.

Best regards,

Santi
 
K

Keith Thompson

Santiago Urueña said:
Santiago said:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:
warning: assignment from incompatible pointer type
This is the code:
const char msg[] = "Test message";
const char *message(void) {
return msg;
}

msg is an array. &msg is a pointer to msg.
I'm not a language lawyer, but the & operator returns the _address_ of
an object, not the pointer. But in this case 'msg' is directly the
address of the array.

Given an object obj, the phrases "a pointer to obj" and "the address
of obj" are synonymous.

Since msg is declared as an array, the expression '&msg' is the
address *of the array*, whereas the expression 'msg' (in most
contexts) yields the address of the arrsy's first element, the same as
'&msg[0]'.

[...]

Section 6 of the comp.lang.c FAQ is an excellent resource.

There's a program called "cdecl" that you might also find useful (if
you can find and install it).
 
R

Richard

Keith Thompson said:
Santiago Urueña said:
Santiago Urueña wrote:
I tried to return a pointer to a constant string, but the compiler
gives the following warning if a cast is not used:

warning: assignment from incompatible pointer type

This is the code:

const char msg[] = "Test message";

const char *message(void) {
return msg;
}

msg is an array. &msg is a pointer to msg.
I'm not a language lawyer, but the & operator returns the _address_ of
an object, not the pointer. But in this case 'msg' is directly the
address of the array.

Given an object obj, the phrases "a pointer to obj" and "the address
of obj" are synonymous.

Since msg is declared as an array, the expression '&msg' is the
address *of the array*, whereas the expression 'msg' (in most
contexts) yields the address of the arrsy's first element, the same as
'&msg[0]'.

I'm a bit sleepy at the moment and understand the above, but in what
cases are &msg[0] and msg not the same in real live systems where they
are 32 or 64 bit pointers?
[...]

Section 6 of the comp.lang.c FAQ is an excellent resource.

There's a program called "cdecl" that you might also find useful (if
you can find and install it).
 
E

Eric Sosman

Richard wrote On 09/19/07 12:54,:
Keith Thompson said:
[...]
Since msg is declared as an array, the expression '&msg' is the
address *of the array*, whereas the expression 'msg' (in most
contexts) yields the address of the arrsy's first element, the same as
'&msg[0]'.

I'm a bit sleepy at the moment and understand the above, but in what
cases are &msg[0] and msg not the same in real live systems where they
are 32 or 64 bit pointers?

In all cases.

An array and its [0] element begin at the same memory
address, always, but the "address-of" an array has a
different type than the "address-of" its [0] element.

IMHO the Standard is unnecessarily confusing here.
In ordinary computer jargon, an address just designates
a memory location and says nothing about what is found
there. A C pointer, on the other hand, also describes
the data type that occupies the pointed-to location (and
perhaps a few neighbors). By naming unary `&' as the
"address-of operator" the Standard steers people toward
the location-only mind-set, whereas unary `&' actually
yields a full-fledged C pointer complete with type. A
name like "pointer-to operator" would have been better.

I'll repeat Keith's suggestion to read Section 6 of
the FAQ, and add that Question 6.12 is exactly what you
have asked.
 
R

Richard

Eric Sosman said:
Richard wrote On 09/19/07 12:54,:
Keith Thompson said:
[...]
Since msg is declared as an array, the expression '&msg' is the
address *of the array*, whereas the expression 'msg' (in most
contexts) yields the address of the arrsy's first element, the same as
'&msg[0]'.

I'm a bit sleepy at the moment and understand the above, but in what
cases are &msg[0] and msg not the same in real live systems where they
are 32 or 64 bit pointers?

In all cases.

In what cases are the VALUES not the same. I am not talking the
types. hence I mentioned the pointers or addresses.
 
R

Richard Heathfield

Eric Sosman said:
Richard wrote On 09/19/07 12:54,:
[...] in what
cases are &msg[0] and msg not the same in real live systems where they
are 32 or 64 bit pointers?

In all cases.

Not so. &msg[0] and msg are identical when their value is used in an
expression.
An array and its [0] element begin at the same memory
address, always, but the "address-of" an array has a
different type than the "address-of" its [0] element.

So you're not really talking about &msg[0] and msg, but &msg[0] and &msg.

If the question is suitably modified, your answer becomes correct.

<snip>
 
E

Eric Sosman

Richard wrote On 09/19/07 14:37,:
Richard wrote On 09/19/07 12:54,:
[...]
Since msg is declared as an array, the expression '&msg' is the
address *of the array*, whereas the expression 'msg' (in most
contexts) yields the address of the arrsy's first element, the same as
'&msg[0]'.

I'm a bit sleepy at the moment and understand the above, but in what
cases are &msg[0] and msg not the same in real live systems where they
are 32 or 64 bit pointers?

In all cases.


In what cases are the VALUES not the same. I am not talking the
types. hence I mentioned the pointers or addresses.

A value is the "precise meaning of the contents of an
object when interpreted as having a specific type" (3.17).
So if you're "not talking the types," you can't be talking
about the values; values in C always have types.

However, I see that I've misread your question and I
apologize if that's created confusion. Keith wrote about
the difference between `&msg' and `msg', the latter being
usually the same as `&msg[0]'. You asked how `&msg[0]'
and `msg' could be different, but with Keith's prose fresh
in mind I managed to insert a non-existent `&' and wrote
as if you had asked how `&msg[0]' and `&msg' could be
different. Cue sound effect: self-administered dope slap.

So, *now* what I think you were asking about was Keith's
"in most contexts." There are two contexts where they could
be different:

When they are the operand of the sizeof operator.
`sizeof &msg[0]' is the number of bytes in a pointer
to an element of the array, and `sizeof msg' is the
number of bytes in the array itself. These could be
identical, but only by coincidence.

When they are the operand of the unary `&' operator.
`& &msg[0]' is a constraint violation, while `& msg'
is a pointer to the array (different in type from a
pointer to the array's first element, but referring
to the same starting byte).

Again, sorry for the mixup.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top