By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,081 Members | 1,885 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,081 IT Pros & Developers. It's quick & easy.

String literal and const

P: n/a
al
char s[] = "This string literal";

or

char *s= "This string literal";

Both define a string literal. Both suppose to be read-only and not to be
modified according to Standard. And both have type of "const char *".
Right? But why does the compiler I am using allow s to be modified, instead
of generating compile error?

Lets say a function declared: void funct1(char sss[]); to accept a char
string as argument. Why does it also accept a string literal, s, above?

To declare a function as: void funct2(const char sss[]); Does this restrict
what kinds of char string passed into sss at all, or does it just imply that
sss will not be modified in "funct2"?

Does Standard define something like: void funct3(char sss[] const) since I
saw some code like that but not sure what it means?

Thanks!


Nov 14 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
"al" <al***@168.net> writes:
char s[] = "This string literal";

or

char *s= "This string literal";

Both define a string literal.
Neither defines a string literal; a string literal is not
something that is defined or even declared. Both define objects
that are strings.
Both suppose to be read-only and not to be modified according
to Standard.
No, only the latter is read-only.
And both have type of "const char *".
No, neither has type const char *. The former has type char []
and the latter has type char *, just as their declarations say.
Right? But why does the compiler I am using allow s to be
modified, instead of generating compile error?
The compiler isn't required to detect the undefined behavior in
attempting to modify the latter, and it's fine to modify the former.
Lets say a function declared: void funct1(char sss[]); to accept a char
string as argument. Why does it also accept a string literal, s, above?
When a function is declared to take an array as its parameter,
the actual type accepted is a pointer type; e.g. an equivalent
declaration is void funct1(char *sss);

s (which is not a string literal) either has type char *, in
which case there's no problem, or it has type char [], in which
case the compiler converts s into a pointer to its first element
(as is done in most cases where the name of an array is
mentioned) and the resulting char * is passed.
To declare a function as: void funct2(const char sss[]); Does this restrict
what kinds of char string passed into sss at all, or does it just imply that
sss will not be modified in "funct2"?
Unfortunately, it doesn't say either. It is more of a social
contract: by declaring the parameter to be const, you promise not
to modify the elements of the array within the function. The
compiler will help you out by diagnosing attempts to modify its
elements, but it is always possible to circumvent these using
casts, or by other ways to access the same array (e.g. via global
variables).
Does Standard define something like: void funct3(char sss[] const) since I
saw some code like that but not sure what it means?


No, that's invalid syntax. There is a similar syntax for
pointers: void funct3(char *const sss); That syntax means that
the function will not modify its pointer, not that it won't
modify what is pointed to.
--
"When I have to rely on inadequacy, I prefer it to be my own."
--Richard Heathfield
Nov 14 '05 #2

P: n/a
al wrote:
char s[] = "This string literal";
This creates an array of char called `s', which is initialized with the
string literal "This string literal".
or

char *s= "This string literal";
This creates a pointer to char called `s' which is initialized to
*point* to the string literal "This string literal".

Note the difference. The former is an *array* with an initializer, the
latter merely a pointer.

Both define a string literal. Both suppose to be read-only and not to be
modified according to Standard. And both have type of "const char *".
Right? But why does the compiler I am using allow s to be modified, instead
of generating compile error?
See above.

Lets say a function declared: void funct1(char sss[]); to accept a char
string as argument. Why does it also accept a string literal, s, above?
Why not? Remember, unlike the situation at the top of my reply, in the
context of a function signature, `type x[]' and `type * x' are
completely equivalent.

To declare a function as: void funct2(const char sss[]); Does this restrict
what kinds of char string passed into sss at all, or does it just imply that
sss will not be modified in "funct2"?


The latter. You can always pass a non-const object as a const.

HTH,
--ag
--
Artie Gold -- Austin, Texas
Oh, for the good old days of regular old SPAM.

Nov 14 '05 #3

P: n/a
al wrote:
char s[] = "This string literal";

or

char *s= "This string literal";

Both define a string literal. Both suppose to be read-only and not to be
modified according to Standard. And both have type of "const char *".
No, neither has type "const char *". The first declares an array
which contains the characters 'T', 'h', etc. The second declares a
pointer initialized to point to a non-modifiable array of char. None
of the objects involved is const-qualified, although the second is
non-modifiable.
Right? But why does the compiler I am using allow s to be modified, instead
of generating compile error?
No error is required in either case. The first `s' may be freely
modified - it's just a normal array of char, but with special syntax
for initialization. The second `s' may not be modified, but the
compiler is, unfortunately, not required to detect attempted
modifications. If you write:

char const *s = "This string literal";

then the compiler is obliged to detect attempts to write to the string
object through `s'.
Lets say a function declared: void funct1(char sss[]); to accept a char
string as argument. Why does it also accept a string literal, s, above?
String literals have type "array of N char".
To declare a function as: void funct2(const char sss[]); Does this restrict
what kinds of char string passed into sss at all, or does it just imply that
sss will not be modified in "funct2"?
Neither. The above declares `funct2' as expecting a pointer to const
char. There are automatic conversions to this type from pointer to
char, array of char and array of const char. Further, `funct2' may
still modify the argument by casting away the constness.
Does Standard define something like: void funct3(char sss[] const) since I
saw some code like that but not sure what it means?
That's not valid syntax. You may be thinking of `void funct3(char
*const sss)', which, when used in a function definition, declares the
parameter itself as non-modifiable. (If the prototype is not a
definition then the `const' has no effect). In other words, the
compiler must complain about

void funct3(char *const sss) {
sss = "Something else";
}

but is not required to complain about

void funct3(char *const sss) {
*sss = 'S';
}
Thanks!


You're welcome.

Jeremy.
Nov 14 '05 #4

P: n/a
al wrote:
char s[] = "This string literal";

or

char *s= "This string literal";

Both define a string literal.
Wrong, they define
in one case an char array initialized with a string literal
in the other a pointer to char initialized to point at a string literal
Both suppose to be read-only and not to be
modified according to Standard.
Wrong, there is nothing "read-only" about the char array.
And both have type of "const char *".
Wrong, neither has type "const char *".
Right?


Not even close.


--
Martin Ambuhl

Nov 14 '05 #5

P: n/a
In article <news:XE**********************@bgtnsc05-news.ops.worldnet.att.net>
al <al***@168.net> writes:
char s[] = "This string literal";
or
char *s= "This string literal";

Both define a string literal. ...
Actually, neither defines a string literal. Even more precisely,
string literals *cannot* be defined. String literals are, instead,
merely source-code constructs, much like tokens and character-constants
(remember that the latter are simply ways to write constants of
type "int", in C).
Both suppose to be read-only and not to be modified according to
Standard.
With one or two exceptions, a string literal produces an anonymous
array of type "array N of char" (where N is one more than the number
of chars in the quotes, after escape-sequence interpretation and
string-literal concatenation and so forth) that is in principle
read-only, and thus the programmer should not attempt to modify
it, yes.
And both have type of "const char *". Right?
No.

Again, the array the compiler whisks up, on seeing a string literal
that is not one of these special exceptions, has type "array N of
char", not "array N of const char". And -- per The Rule about
arrays and pointers in C -- an object of type "array N of T" often
becomes a value of type "pointer to T". In this case, that would
be a value of type "pointer to char" or "char *" -- i.e., no "const".

(C and C++ differ greatly here, incidentally. Be sure you are
using a C compiler, not a C++ compiler.)

But there are those pesky exceptions. The big exception for string
literals occurs when using one as an initializer:

char sa[] = "initialized";
char *sp = "initialized";

The initializer for "sa" *is* one of these exceptions; the initializer
for "sp" is *not* one of these exceptions.

When a string literal is used to initialize an object of type "array
N of char", or "array FILL_IN_SIZE_AUTOMATICALLY_PLEASE of char",
or "array (N or FILL_IN...) of const char", the string literal does
not create an anonymous object [see also footnote]. Instead, it
simply fills in the named "array of char" or "array of const char"
object it is initializing. The type of the array, and its size if
this is specified, override the usual effects, so that the array
has its read/write or read-only state set by the programmer. If
the size is specified and is *much* too small, a diagnostic is
required; but if the size is specified and is one character too
small to hold the string, the trailing '\0' is omitted:

char four[4] = "four"; /* has no terminating '\0'! */

In the case of:

char sa[] = "initialized";

the array's size is left for the compiler to fill in, so the array
has size 12 (if I counted correctly), just large enough to hold
the sequence {'i', 'n',' ..., 'e', 'd', '\0'}. Thus, here, "sa"
has type "array 12 of char" and is read/write -- sa[i], where i is
in [0..12), can be replaced with a new value.

In the case of "sp", however, we have:

char *sp = "initialized";

Here "sp" has type "pointer to char", not "array of (possibly
qualified) char", so the string literal goes ahead and produces
an anonymous (unnamed) array, "array 12 of char", that is in
principle read-only. This array "decays", as the FAQ puts it,
to a value of type "pointer to char", pointing to the first
element of the unnamed array -- the first letter 'i'. The
variable "sp" is then initialized to point to that 'i'.
But why does the compiler I am using allow s to be modified, instead
of generating compile error?
In the quote above, you have *two* variables named 's'; which
one do you mean, and modified in what way?

Given sa and sp as defined above, this is valid:

sp = "a different literal";

Here the string literal generates an anonymous array as usual, and
the variable sp is modified to point to its first 'a', via the
usual "decay" trick (that which I call "The Rule about pointers
and arrays in C"; see also http://web.torek.net/torek/c/index.html
and sub-pages.) But:

sp[3] = 'x';

is *not* valid, even though no diagnostic is required.

On the other hand:

sa = "error";

is *not* valid, and a diagnostic is required, because sa has type
"array 12 of char" and is thus not what the Standard calls a
"modifiable lvalue". At the same time:

sa[3] = 'x';

*is* valid, and merely changes the fourth letter (subscript 3) in
the array.
Lets say a function declared: void funct1(char sss[]); to accept a char
string as argument. Why does it also accept a string literal, s, above?
Due to The Rule plus the fact that C passes all arguments by
value, the declaration:

void funct1(char sss[]);

"means" exactly the same thing as the declaration:

void funct1(char *sss);

That is, the function takes a single argument value of type "pointer
to char". As I noted above, a string literal normally produces an
anonymous object of type "array N of char", and The Rule converts
objects of type "array N of T" into values of type "pointer to T".
If T is "char", this is a value of type "pointer to char", which
is precisely what funct1() requires.
To declare a function as: void funct2(const char sss[]); Does this restrict
what kinds of char string passed into sss at all, or does it just imply that
sss will not be modified in "funct2"?
This declaration "means" the same thing as:

void funct2(const char *sss);

The const qualifier largely means "read-only", not "constant"; and
yes, this implies -- but does not guarantee! -- that funct2() will
not write on sss[i]. It does not mean that sss[i] must *be*
read-only; it only says -- weakly -- that funct2() itself will not
write on it. Some *other* function might write on it at any time,
and funct2() cannot in general depend on sss[i] not changing.
(This sort of optimization problem is what led to C99's "restrict".
Combine "restrict" with "const" and funct2() *can* depend on it,
allowing a C compiler to generate smaller and/or faster code.)
Does Standard define something like: void funct3(char sss[] const) since I
saw some code like that but not sure what it means?


No. The "const" qualifier can move slightly:

void f(const char *);
void f(char const *);

both "mean" the same thing. If you use the array syntax for
formal parameters -- I prefer not to, becaues the compiler just
has to rewrite it internally anyway -- these are the only
possible placements:

void f(const char []);
void f(char const []);

(the identifiers are always optional in prototypes). Using
the pointer syntax, however, it is possible to add another
const:

void f(char const * const);

and:

void f(char const * const p) {
...
}

The second "const" in the prototype has no effect. THe second
"const" in the definition affects "p", making the variable p itself
read-only. This is the same as if we were to write:

void f(char const *p0) {
char const * const p = p0;
...
}

The trick here is that any formal parameter in any function acts
just like an ordinary local variable inside that function. It is
automatically initialized with the value delivered by whoever calls
the function. If the formal parameter (here p) is labeled "const",
it is a read-only variable, just like any other "const" in C:

const int i = 3;
const double pi = 3.141592653589793238462643383279502884;

Here "i" and "pi" are not constants, just variables that you are
forbidden to change! (The semantic difference shows up in all
kinds of places, e.g.:

% cat error.c
const int i = 3;
char a[3];
char b[i];
%

The third line is invalid and must draw a diagnostic, even in C99
with its variable length arrays. Although "i" is "const", it is
not a constant. Again, C++ is quite different here.)

[footnote] [dig out C99 standard and check on string literals,
should allow volatile qualifiers too I believe. Note case of sizeof
"foo"; note that a compiler can still generate the anonymous array,
wasting space in an executable image, but the only way you can find
out it did so is to step outside the C standard.]
[Sorry, no time to fill out footnote -- must dash]
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #6

P: n/a
On 19 Dec 2003 11:59:55 -0800, Ben Pfaff <bl*@cs.stanford.edu> wrote
in comp.lang.c:
"al" <al***@168.net> writes:
char s[] = "This string literal";

or

char *s= "This string literal";

Both define a string literal.


Neither defines a string literal; a string literal is not
something that is defined or even declared. Both define objects
that are strings.
Both suppose to be read-only and not to be modified according
to Standard.


No, only the latter is read-only.


[snip]

To be pedantic, the standard says nothing at all about whether string
literals are read-only. In fact, unlike the C++ standard, it very
specifically does not call the characters in the array const.

Attempting to modify a string literal in C is undefined behavior
because the standard makes a very specific statement to that effect.
It does not arise out of any other characteristics defined for
literals.

On many implementations it is quite possible to modify a string
literal, so they are not read-only. On many others it is impossible.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
Nov 14 '05 #7

P: n/a
Jack Klein <ja*******@spamcop.net> writes:
On 19 Dec 2003 11:59:55 -0800, Ben Pfaff <bl*@cs.stanford.edu> wrote
in comp.lang.c:
"al" <al***@168.net> writes:
char s[] = "This string literal";

or

char *s= "This string literal";

No, only the latter is read-only.


[snip]

To be pedantic, the standard says nothing at all about whether string
literals are read-only. In fact, unlike the C++ standard, it very
specifically does not call the characters in the array const.

Attempting to modify a string literal in C is undefined behavior
because the standard makes a very specific statement to that effect.
It does not arise out of any other characteristics defined for
literals.

On many implementations it is quite possible to modify a string
literal, so they are not read-only. On many others it is impossible.


I don't understand the distinction you're trying to make here. I
didn't call the characters "const", and they certainly are not
const. I called them read-only because behavior is undefined
when you try to write to them. This is exactly the same as what
you get when you try to write to "const" data. Both string
literals and const data are effectively read-only in portable
code.
--
"The lusers I know are so clueless, that if they were dipped in clue
musk and dropped in the middle of pack of horny clues, on clue prom
night during clue happy hour, they still couldn't get a clue."
--Michael Girdwood, in the monastery
Nov 14 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.