const char*

P

Paul Emmons

In writing a function similar to strstr(), I'm calling both of the
arguments "const char *". My compiler (gcc) complains
"warning: return discards qualifiers from pointer target type"
unless I have the function return "const char*" as well
(rather than just "char *").

In turn, any pointer receiving this value when calling the function
must also be "const char *" or the compiler will complain,
"warning: assignment discards qualifiers from pointer target type".

This propogation of the attribute gets rather burdensome,
especially in that one might want to use the function on strings
that are not really constant.

How far along is it important to worry about this? When should one
drop the attribute, e.g. with a cast in the return statement: "return
(char *) p," so that the return value can be merely "char * "?

We can see that library functions such as strstr() and strchr()
themselves do not return const char pointers, even though
they always (if not null) point to a character within their const char
arguments. Is this the best point at which to go and do likewise?
 
E

E. Robert Tisdale

Paul said:
In writing a function similar to strstr(),

char *strstr(const char *haystack, const char *needle);
I'm calling both of the arguments "const char *".
My compiler (gcc) complains
"warning: return discards qualifiers from pointer target type"
unless I have the function return "const char*" as well
(rather than just "char *").
In turn,
any pointer receiving this value when calling the function
must also be "const char *" or the compiler will complain,
"warning: assignment discards qualifiers from pointer target type".
This propagation of the attribute gets rather burdensome,
especially in that one might want to use the function
on strings that are not really constant.
How far along is it important to worry about this?
When should one drop the attribute,
e.g. with a cast in the return statement: "return (char*)p,"
so that the return value can be merely "char*"?

Evidently, this is what was done with strstr(const char*, const char*).
We can see that
library functions such as strstr() and strchr() themselves
do not return const char pointers,
even though they always (if not null)
point to a character within their const char arguments.
Is this the best point at which to go and do likewise?

Ideally, there would be two versions

/* 1 */ const
char* strstrConstant(const char*, const char*); // and
/* 2 */ char* strstrVariable( char*, const char*);

The second version corresponds to the original strstr(char*, char*).

It really isn't difficult (burdensome) to implement both versions.
One can easily defined [as an inline function] in terms of the other
by "cast'ing away the const" appropriately (and harmlessly).
Otherwise, you and other programmers who must maintain your code
will be obliged to search through the application
to find the place where you cast away const.
 
M

Martin Ambuhl

Paul said:
In writing a function similar to strstr(), I'm calling both of the
arguments "const char *". My compiler (gcc) complains
"warning: return discards qualifiers from pointer target type"
unless I have the function return "const char*" as well
(rather than just "char *").

You have shown us no code, so it is impossible to answer you questions.
The following program seems to conform to the conditions you state
with _none_ of the untoward diagnostics you claim:

#include <stdio.h>
#include <string.h>

char *function_similar_to_strstr(const char *s, const char *sub)
{
return strstr(s, sub);
}

int main(void)
{
char bigstring[] = "This is the big string to look in.",
substring[] = "string";
char *found;

printf("Looking in\n \"%s\"\nfor \"%s\"\n", bigstring, substring);
found = function_similar_to_strstr(bigstring, substring);
if (found)
printf("found at %p: \"%s\"\n", (void *) found, found);
else
printf("not found\n");
return 0;
}


Looking in
"This is the big string to look in."
for "string"
found at effb8: "string to look in."
 
D

Darrell Grainger

In writing a function similar to strstr(), I'm calling both of the
arguments "const char *". My compiler (gcc) complains
"warning: return discards qualifiers from pointer target type"
unless I have the function return "const char*" as well
(rather than just "char *").

You have not provide code so I'm unable to be sure why gcc is giving you a
warning. If you did something like:

char *my_strstr(const char *s1, const char *s2)
{
/* do some stuff to change s2 but not the contents it references */
return s2;
}

This would generate the warning. I read the strstr() function as a
function that will not alter the strings I pass in. It passes back a
pointer into the second string and lets me change the string.

This implies that the const indicates what strstr() will do but that the
same restriction does not exist for the person calling strstr().
Therefore, I can alter the contents of s2 through the pointer returned by
strstr(). For this, a cast would be necessary. So I'd just cast the return
value.

The cast is appropriate because I have consciously decided that the user
calling strstr() can alter the string if they so wish. The const on the
input parameters is just my way of assuring the user that strstr() will
not alter the contents.
 
E

Eric Sosman

Paul said:
In writing a function similar to strstr(), I'm calling both of the
arguments "const char *". My compiler (gcc) complains
"warning: return discards qualifiers from pointer target type"
unless I have the function return "const char*" as well
(rather than just "char *").

In turn, any pointer receiving this value when calling the function
must also be "const char *" or the compiler will complain,
"warning: assignment discards qualifiers from pointer target type".

This propogation of the attribute gets rather burdensome,
especially in that one might want to use the function on strings
that are not really constant.

How far along is it important to worry about this? When should one
drop the attribute, e.g. with a cast in the return statement: "return
(char *) p," so that the return value can be merely "char * "?

We can see that library functions such as strstr() and strchr()
themselves do not return const char pointers, even though
they always (if not null) point to a character within their const char
arguments. Is this the best point at which to go and do likewise?

It's about the best you can do with C, whose type system
isn't especially expressive. An unattractive alternative is
to write two versions of the function:

const char * my_strstr_c(const char *s1, const char *s2);
char * my_strstr_v(char *s1, const char *s2);

.... but since the caller is at liberty to supply or remove
`const' by casting the returned value, I don't think this
technique really buys very much.
 
E

E. Robert Tisdale

Eric said:
It's about the best you can do with C,
whose type system isn't especially expressive.
An unattractive alternative
is to write two versions of the function:

const char * my_strstr_c(const char *s1, const char *s2);
char * my_strstr_v(char *s1, const char *s2);

... but since the caller is at liberty to supply or remove
`const' by casting the returned value,
I don't think this technique really buys very much.

But it does "buy" something.
It allows the calling program to avoid the caste.
 
P

Paul Emmons

Thank you for your reply. What you say makes sense if the whole
"const" distinction is mainly a matter of documentation. I wonder. I
haven't tried it yet, but what would happen if the first argument to
strstr() points to a string initialized at compile time such as:

char hell[]="Hello, world!";

(outside any function), and then a program did p=strstr(hell, "o");
*p='\0';

Would all hell break loose? :)

Still rather new at programming in the Linux environment, after years
in MS-DOS, I asked an intelligent friend a few months ago how it was
possible that a function possibly destined for a shared library didn't
need to be re-entrant. He explained that the text section (where the
code lives) is shared, while each process (but not each thread) using
the function gets its own copy of the data and bss sections. Hence it
could be very bad indeed if anything in the code section got modified
(and presumably a modern OS, aided by hardware, would slap any process
that tried to do it).

I'm still unclear, however, where hell belongs in that analysis. If
it's really constant, then it's a waste to give each process its own
copy. If I were writing in assembler, I think I could put it in
either .text or .data. So it occurred to me that the "const"
attribute might exist to enforce this very important distinction,
which I could never understand in the naive little world of DOS.

Thanks again!
 
A

Arthur J. O'Dwyer

Thank you for your reply. What you say makes sense if the whole
"const" distinction is mainly a matter of documentation.

'const' acts half as documentation ("Hey, programmer, don't modify
this value!") and half as guarantee ("Hey, computer, I promise never
to modify this value!"). This means that the computer will promise
to make your program work --- and possibly more efficiently --- but
only as long as you keep your promise not to modify the
'const'-qualified value.
I wonder. I
haven't tried it yet, but what would happen if the first argument to
strstr() points to a string initialized at compile time such as:

char hell[]="Hello, world!";

(outside any function), and then a program did p=strstr(hell, "o");

So far, so good.

Whoops! 'p' points into a 'const'-qualified object, so by modifying
'*p', you're breaking your promise to the computer.
Would all hell break loose? :)

Yep. Maybe you'll get a segfault (if the computer catches you
trying to modify the constant value). Maybe the constant value will
silently change! Maybe *other* constant values will silently change!
Maybe *nothing* will change, even though you just told '*p' to become
zero... and that would also be bad!
Still rather new at programming in the Linux environment, after years
in MS-DOS, I asked an intelligent friend a few months ago how it was
possible that a function possibly destined for a shared library didn't
need to be re-entrant. He explained that the text section (where the
code lives) is shared, while each process (but not each thread) using
the function gets its own copy of the data and bss sections. Hence it
could be very bad indeed if anything in the code section got modified
(and presumably a modern OS, aided by hardware, would slap any process
that tried to do it).

Dunno. Ask comp.unix.programming or a Linux group if you want to
know the answer; it has nothing to do with C.
I'm still unclear, however, where hell belongs in that analysis. If
it's really constant, then it's a waste to give each process its own
copy. If I were writing in assembler, I think I could put it in
either .text or .data. So it occurred to me that the "const"
attribute might exist to enforce this very important distinction,
which I could never understand in the naive little world of DOS.

I don't see to what "very important distinction" you're referring,
but I hope I've clarified things enough above that you won't need
me to see it. :)

-Arthur
 
C

CBFalconer

Arthur J. O'Dwyer said:
.... snip ...
I wonder. I haven't tried it yet, but what would happen if the
first argument to strstr() points to a string initialized at
compile time such as:

char hell[]="Hello, world!";

(outside any function), and then a program did
p=strstr(hell, "o");

So far, so good.

Whoops! 'p' points into a 'const'-qualified object, so by
modifying '*p', you're breaking your promise to the computer.

Hold on there. That was a static initialized array, not a
constant unmodifiable string. You would be right if the original
statement had been:

char *hell = "Hello, world!";

However all is copasetic with the original declaration.
 
A

Arthur J. O'Dwyer

Arthur J. O'Dwyer said:
I wonder. I haven't tried it yet, but what would happen if the
first argument to strstr() points to a string initialized at
compile time such as:

char hell[]="Hello, world!";

(outside any function), and then a program did
p=strstr(hell, "o");

So far, so good.

Whoops! 'p' points into a 'const'-qualified object, so by
modifying '*p', you're breaking your promise to the computer.

Hold on there. That was a static initialized array, not a
constant unmodifiable string. You would be right if the original
statement had been:

char *hell = "Hello, world!";

However all is copasetic with the original declaration.

Whoops... you're right. I wasn't reading closely enough, and
then I was assuming the question was more subtle than it really
was. Yes, definitely, modifying a non-const object through a
non-const pointer is allowed in C. If it weren't, what would
be the point?! :)

-Arthur
 
P

Paul Emmons

strstr() points to a string initialized at compile time such as:

char hell[]="Hello, world!";

(outside any function), and then a program did p=strstr(hell, "o");

So far, so good.

Whoops! 'p' points into a 'const'-qualified object, so by modifying
'*p', you're breaking your promise to the computer.
Would all hell break loose? :)

Yep. Maybe you'll get a segfault (if the computer catches you
trying to modify the constant value). Maybe the constant value will
silently change! Maybe *other* constant values will silently change!
Maybe *nothing* will change, even though you just told '*p' to become
zero... and that would also be bad!

I suspected so. (Even though I did try it, using gcc-linux, and it
compiled and ran without anybody complaining). So you've confirmed my
larger suspicion. But please note, it all stems from the fact that
strstr() returns a char *, not a const char *. So is it really my
fault?
 
L

lawrence.jones

CBFalconer said:
Hold on there. That was a static initialized array, not a
constant unmodifiable string. You would be right if the original
statement had been:

char *hell = "Hello, world!";

Nope. Although string literals are not modifiable, their base type is
(for historical reasons) just char rather than const char.

-Larry Jones

Well, it's all a question of perspective. -- Calvin
 

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

Staff online

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top