assigning string constant to char *

S

Steve Pope

The first of the following functions compiles, the second gives what
I think is a spurious error:

"cannot convert `const char[5]' to `char *' in assignment".

void foo(int m) {
char *str;
if (m < 4) str = "%01x";
else if (m < 9) str = "%02x";
else str = "%03x";
}

void foo(int m) {
char *str;
str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
}

Any idea why gcc doesn't like the second version? If I compile
it as a C file instead of C++, it works fine.

Steve
 
T

Thomas Tutone

Steve said:
The first of the following functions compiles, the second gives what
I think is a spurious error:

"cannot convert `const char[5]' to `char *' in assignment".

void foo(int m) {
char *str;
if (m < 4) str = "%01x";
else if (m < 9) str = "%02x";
else str = "%03x";
}

void foo(int m) {
char *str;
str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
}

Any idea why gcc doesn't like the second version? If I compile
it as a C file instead of C++, it works fine.

It is not a spurious error, just an obscure one. A string constant
(like "%01x") is actually of type const char[5], which decays to const
char*. For historical reasons (so as not to break a lot of existing
code), you can assign a string constant to a non-const char*, although
it bends (if not breaks) const-correctness. In the first example, you
are assigning a string constant to a char*, and that's permitted. In
the second example, you are assigning not a string constant, but an
expression instead, to the char*. That's not permitted - the exception
to const-correctness is intentionally kept narrow.

To solve your problem change your second example to the following:

void foo(int m) {
const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
}

Since you're now assigning to a const char*, not to a non-const char*,
the problem disappears.

Best regards,

Tom
 
S

Steve Pope

Thomas Tutone said:
Steve Pope wrote:
It is not a spurious error, just an obscure one. A string constant
(like "%01x") is actually of type const char[5], which decays to const
char*. For historical reasons (so as not to break a lot of existing
code), you can assign a string constant to a non-const char*, although
it bends (if not breaks) const-correctness. In the first example, you
are assigning a string constant to a char*, and that's permitted. In
the second example, you are assigning not a string constant, but an
expression instead, to the char*. That's not permitted - the exception
to const-correctness is intentionally kept narrow.

Okay, that makes sense.
To solve your problem change your second example to the following:
void foo(int m) {
const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
}
Since you're now assigning to a const char*, not to a non-const char*,
the problem disappears.

That works, but oddly so does the following:

const char *str;
str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
if (m > 12) str = "%04x";

It seems the "const" does not mean as much for type char * as
it does for other types.

Steve
 
Z

zeppe

Steve said:
It seems the "const" does not mean as much for type char * as
it does for other types.

It's an issue related not to the char type, but to the string literals:
the following conversion are allowed:
string literal -> const char*
string literal -> char* // deprecated, but valid

but, of course, it's not valid
const char* -> char*

so, you can convert string literal to char* only directly, not through
const char* (as you tried with the conditional operator '?').

Bye,

Zeppe
 
P

peter koch

Steve Pope skrev:

[snip]
Okay, that makes sense.




That works, but oddly so does the following:

const char *str;
str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
if (m > 12) str = "%04x";

It seems the "const" does not mean as much for type char * as
it does for other types.

Well no.... as Thomas Tutone explained, you can break constness for
char only. But what surprises you above is that you can reassign str.
This is because you read the type wrongly. const char *str means that
str is a pointer to a constant char. The pointer is by itself not
constant - you can assign it to anything you want (and actually you
should be surprised by both assignments above). If you wanted the
pointer to be constant, the notation would have to be char * const str
(and then you better remember to initialise it!). This way the content
of *str would be changeable.

/Peter
 
T

Thomas Tutone

Steve said:
[snip]
It is not a spurious error, just an obscure one. A string constant
(like "%01x") is actually of type const char[5], which decays to const
char*. For historical reasons (so as not to break a lot of existing
code), you can assign a string constant to a non-const char*, although
it bends (if not breaks) const-correctness. In the first example, you
are assigning a string constant to a char*, and that's permitted. In
the second example, you are assigning not a string constant, but an
expression instead, to the char*. That's not permitted - the exception
to const-correctness is intentionally kept narrow.

Okay, that makes sense.
To solve your problem change your second example to the following:
void foo(int m) {
const char *str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
}
Since you're now assigning to a const char*, not to a non-const char*,
the problem disappears.

That works, but oddly so does the following:

const char *str;
str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
if (m > 12) str = "%04x";

It seems the "const" does not mean as much for type char * as
it does for other types.

Sorry, my changing your example so that the str was initialized upon
creation confused matters. A const char* means "a pointer to a char
that is const," not "a const pointer to a char." The latter would be
char* const. You can reassign a const char*, you just can't change the
contents of what it points to.

Best regards,

Tom
 
V

Victor Bazarov

Steve said:
That works, but oddly so does the following:

const char *str;
str = m < 4 ? "%01x" : m < 9 ? "%02x" : "%03x";
if (m > 12) str = "%04x";

It seems the "const" does not mean as much for type char * as
it does for other types.

You confuse your consts. In

const char * str;

'const' relates to the char, not to the char*. You need to read up on
declaration syntax and its meaning.

V
 
S

Steve Pope

zeppe said:
Steve Pope wrote:
It's an issue related not to the char type, but to the string
literals: the following conversion are allowed:
string literal -> const char*
string literal -> char* // deprecated, but valid

but, of course, it's not valid
const char* -> char*

so, you can convert string literal to char* only directly, not through
const char* (as you tried with the conditional operator '?').

Seems that *is* related to the type char *, since the following
code also compiles, whereas analogous code with str of any type
other than char * does not compile. To me it looks like gcc
at least has special-cased "const char *" to not actually be const.

char a[10], b[10];

void foo(int m) {
const char *str;
str = a;
if (m > 12) str = b;
}

Cheers,


Steve
 
V

Victor Bazarov

Steve said:
[..] To me it looks like gcc
at least has special-cased "const char *" to not actually be const.

char a[10], b[10];

void foo(int m) {
const char *str;
str = a;
if (m > 12) str = b;
}

There you go again... 'str' is a non-const pointer to const char.
You can assign new value to it from an array (which when used in
an exrpession like assignment above decays to a pointer to char).

If you want 'str' to be non-changeable pointer, you need to declare
*it itself* const:

char * const str;

V
 
Z

zeppe

Seems that *is* related to the type char *, since the following
code also compiles, whereas analogous code with str of any type
other than char * does not compile. To me it looks like gcc
at least has special-cased "const char *" to not actually be const.

char a[10], b[10];

void foo(int m) {
const char *str;
str = a;
if (m > 12) str = b;
}

Actually, this is the opposite cast, i.e.:
char* -> const char*

that of course is correct (and the above code works also with int*,
double* and any other pointer).
BTW, it seems that we are talking about two different things: I was
explaining the strange behaviour due to the conversion from literal to
char*, and you are referring to the fact that is seems possible o change
value to a const variable (that is, as others explained, is not const,
but it's const the value the pointer is referring to).


Bye,

Zeppe
 
S

Steve Pope

peter koch said:
But what surprises you above is that you can reassign str.
This is because you read the type wrongly. const char *str means that
str is a pointer to a constant char. The pointer is by itself not
constant - you can assign it to anything you want (and actually you
should be surprised by both assignments above). If you wanted the
pointer to be constant, the notation would have to be char * const str
(and then you better remember to initialise it!).

Thanks, that does explain my confusion here.

Steve
 

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,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top