why is this variable read-only

S

saurabh

Please have a look at following snippet..

#include<stdio.h>
int main()
{
char* a="foo";
char * b="bar";
*a=*b;
/* I know above line has undefined behaviour,because *a and *b are
read only ,my question is why?I understand that a and b are locals and
will be allocated on main's stack frame.Then why can't I modify them
*/
return 0;
}
 
K

Keith Thompson

saurabh said:
Please have a look at following snippet..

#include<stdio.h>
int main()
{
char* a="foo";
char * b="bar";
*a=*b;
/* I know above line has undefined behaviour,because *a and *b are
read only ,my question is why?I understand that a and b are locals and
will be allocated on main's stack frame.Then why can't I modify them
*/
return 0;
}

a and b (pointer objects) are not read-only. *a and *b (char
objects) are read-only.

a and b are objects with automatic storage duration, declared within
the body of main. On many implementations, this means that they'll
be allocated on main's stack frame.

A string literal, on the other hand, specifies an array object
with static storage duration (it exists for the entire lifetime of
the program), and attempting to modify that array object invokes
undefined behavior. (It would have made more sense for these objects
to be const-qualified, but string literals existed before the "const"
qualifier was introduced to the language.) *a is the first element
of one such array object, so you're not allowed to modify it.
 
A

arnuld

Please have a look at following snippet..

#include<stdio.h>
int main()
{
        char* a="foo";
        char * b="bar";
        *a=*b;
/* I know above line has undefined behaviour,because *a and *b are
read only ,my question is why?I understand that a and b are locals and
will be allocated on main's stack frame.Then why can't I modify them
*/


You can if your compiler allows so: FAQ 1.32. Also see 6.2. BTW, in
your code I will use const char* rather than char* .
 
S

saurabh

Thanks a lot for your answer.
I got it.
But I have another doubt i.e. If I execute that line (char*
a="Sme_big_string_literal";)in a while loop ,will I eventually fill up
the whole memory?
 
I

Igmar Palsenberg

saurabh said:
Thanks a lot for your answer.
I got it.
But I have another doubt i.e. If I execute that line (char*
a="Sme_big_string_literal";)in a while loop ,will I eventually fill up
the whole memory?

No, since that string is a constant.



Igmar
 
B

Beej Jorgensen

saurabh said:
int main()
{
char* a="foo";
char * b="bar";
*a=*b;
/* I know above line has undefined behaviour,because *a and *b are
read only ,my question is why?I understand that a and b are locals and
will be allocated on main's stack frame.Then why can't I modify them
*/

a and b are local to main(), but the real question is this: where are
"foo" and "bar" allocated?

It's probably not in main()'s stack frame--or even on the stack. It'll
likely be elsewhere.

Check this out:

#include <stdio.h>

void foo(void) { char *a = "beej"; printf("%p\n", (void*)a); }
void bar(void) { char *b = "beej"; printf("%p\n", (void*)b); }

int main(void)
{
foo();
bar();
return 0;
}

prints this on my machine:

0x40061c
0x40061c

foo()'s a and bar()'s b point to the same address! Good thing foo()
can't modify what a points at, or it would have changed in bar(), too!
(This is a system-dependent result.)

-Beej

ObPedantry: stack
 
A

arnuld

a and b (pointer objects) are not read-only.  *a and *b (char
objects) are read-only.

qualifier was introduced to the language.) *a is the first element
of one such array object, so you're not allowed to modify it.


I checked FAQ 1.32 (which says "may be stored in read-only memory")
and I also checked the standard (section 6.4.5, n1256) which says "the
behavior is undefined". Now do UB and "not allowed to modify" have
same meaning ?
 
T

Thomas Matthews

saurabh said:
Please have a look at following snippet..

#include<stdio.h>
int main()
{
char* a="foo";
char * b="bar";
*a=*b;
/* I know above line has undefined behaviour,because *a and *b are
read only ,my question is why?I understand that a and b are locals and
will be allocated on main's stack frame.Then why can't I modify them
*/
return 0;
}
As far as where the strings are stored, could
be anywhere.

I used a compiler that would store the strings in read-only
memory and copy them onto the stack. The only method to
access the strings directly from read-only memory was to
declare them as "static const":

#include <stdio.h>

int main()
{
static const char * a = "foo";
static const char * b = "bar";
fprintf(stdout, "String a[%p] = \"%s\"\n", a, a);
fprintf(stdout, "String b[%p] = \"%s\"\n", b, b);
return 0;
}

Try the above program. Print the assembly language.
Remove the "static const". Print assembly language.
Compare the two prints of the assembly language.

{You could also use a debugger and step through the
assembly code.}

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.comeaucomputing.com/learn/faq/
Other sites:
http://www.josuttis.com -- C++ STL Library book
http://www.sgi.com/tech/stl -- Standard Template Library
 
C

Chris Dollin

saurabh said:
Please have a look at following snippet..

#include<stdio.h>
int main()
{
char* a="foo";
char * b="bar";
*a=*b;
/* I know above line has undefined behaviour,because *a and *b are
read only ,my question is why?

To give the compiler the freedom to allocate the strings in
read-only memory.
I understand that a and b are locals and
will be allocated on main's stack frame.

They're locals, but they need not be allocated in the
stack frame. For example, they could be in machine
registers.
Then why can't I modify them
*/

You can modify `a` and `b` all you like. It's `*a` and `*b`
that are read-only [1].
return 0;
}

[1] Well, technically they're not "read-only"; it's just that
writing to them gives you Undefined Behaviour. The change
might stick, it might be ignored, it might raise some sort
of error, it might trash some critical device register, or
it might cross the streams. So, don't do that.

--
"I'm far too ditzy to grasp the subtleties of mockery." Raven,
/Questionable Content/

Hewlett-Packard Limited registered no:
registered office: Cain Road, Bracknell, Berks RG12 1HN 690597 England
 
J

James Kuyper

arnuld said:
I checked FAQ 1.32 (which says "may be stored in read-only memory")
and I also checked the standard (section 6.4.5, n1256) which says "the
behavior is undefined". Now do UB and "not allowed to modify" have
same meaning ?

No. "not allowed to modify" would mean that you couldn't modify it, as
such, it's not really a correct description of this case. UB means that
you can try to modify it, and might actually succeed. However, because
your program makes the attempt, the standard imposes no constraints on
it's behavior. That's your entire program whose behavior is undefined,
not just the lines of code where the attempt is actually made.

As a general rule, you want your program's behavior constrained; either
by the C standard, or by some other standard, or at least by your
particular implementation. If none of those apply, there's not much
point in bothering to run the program.

A stricter language standard would mandate rejection of code that
attempts certain things, and in that case it would be meaningful to say
"you're not allowed to do this", but that's not the way the C standard
was written. The only code a conforming implementation of C is required
to reject is code which contains a #error directive that survives
conditional compilation.
 
J

James Kuyper

Noob said:
Doesn't this make 'a' static instead of auto?

Yes. That's the point. "foo" causes allocation of a static array of char
that cannot be modified. Therefore, it can make sense (at least in some
contexts) for a pointer to that memory to be static as well.
 
K

Keith Thompson

arnuld said:
I checked FAQ 1.32 (which says "may be stored in read-only memory")
and I also checked the standard (section 6.4.5, n1256) which says "the
behavior is undefined". Now do UB and "not allowed to modify" have
same meaning ?

"not allowed to modify" was slightly sloppy wording. In fact,
attempting to modify it invokes undefined behavior; you definitely
shouldn't do it, but the implementation is not obliged to stop you.
 
B

Barry Schwarz

You can if your compiler allows so: FAQ 1.32. Also see 6.2. BTW, in
your code I will use const char* rather than char* .

Only if your code will never be processed by any other compiler or
even this compiler after updates have been applied. And what do you
think the result will be if later in your code you have
puts("foo");
and how much fun would you have debugging it?

Since there is no text in 6.2 itself and none of its subsections deal
with string literals, which part of 6.2 do you think has any relevance
to the question asked?
 
B

Barry Schwarz

As far as where the strings are stored, could
be anywhere.

I used a compiler that would store the strings in read-only
memory and copy them onto the stack. The only method to
access the strings directly from read-only memory was to
declare them as "static const":

#include <stdio.h>

int main()
{
static const char * a = "foo";

The static storage class specification does not change the attributes
of the strings. They were static in the original code and remain
static is this code.

It does change the attributes of a. Before it was automatic, would
come into existence and be initialized each time main was entered,
each instance of main would have its own copy, and go out of
existence when that instance of main exited. Now, a is created and
initialized once before main begins its first execution, is never
initialized again, remains in existence at the same address until the
program terminates, and every instance of main will refer to the same
object.
static const char * b = "bar";
fprintf(stdout, "String a[%p] = \"%s\"\n", a, a);

Better to cast the first a to void*.
fprintf(stdout, "String b[%p] = \"%s\"\n", b, b);
return 0;
}

Try the above program. Print the assembly language.
Remove the "static const". Print assembly language.
Compare the two prints of the assembly language.

{You could also use a debugger and step through the
assembly code.}

Which may give you an idea about what a particular compiler chooses to
do but no idea whether that is in compliance with the standard or
whether a different compiler would do something different.

And since the static specification only affects a and b, not what they
point to, the test would be more meaningful if the last two printf
arguments were (void*)&a and (void*)a.
 
K

Keith Thompson

Barry Schwarz said:
Only if your code will never be processed by any other compiler or
even this compiler after updates have been applied. And what do you
think the result will be if later in your code you have
puts("foo");
and how much fun would you have debugging it?

Since there is no text in 6.2 itself and none of its subsections deal
with string literals, which part of 6.2 do you think has any relevance
to the question asked?

I think he was referring to question 6.2 of the FAQ, not section 6.2
of the standard.
 
J

John Bode

I checked FAQ 1.32 (which says "may be stored in read-only memory")
and I also checked the standard (section 6.4.5, n1256) which says "the
behavior is undefined". Now do UB and "not allowed to modify" have
same meaning ?

No. Invoking undefined behavior simply means you've done something
that the standard explicitly does not address (if that makes any
sense), and that whatever the implementation does in response is the
"right" thing to do. For an implementation that stores string
constants in writable memory, the string constant is modified and life
goes on (assuming you haven't clobbered something else in the
process). For an implementation that stores string constants in read-
only memory, any number of things can happen: an exception may be
thrown, the operation may fail silently, the operation may succeed but
leave the system in a bad state that causes problems later on, etc.
 
K

Keith Thompson

John Bode said:
No. Invoking undefined behavior simply means you've done something
that the standard explicitly does not address (if that makes any
sense), and that whatever the implementation does in response is the
"right" thing to do. For an implementation that stores string
constants in writable memory, the string constant is modified and
life goes on (assuming you haven't clobbered something else in the
process). For an implementation that stores string constants in
read- only memory, any number of things can happen: an exception may
be thrown, the operation may fail silently, the operation may
succeed but leave the system in a bad state that causes problems
later on, etc.

It's even permitted (though unlikely) for an implementation to store
string literals in writable memory, but to share the same memory for
multiple instances of the same literal. Thus this code fragment:

char *s1 = "hello";
char *s2 = "hello";
strcpy(s1, "XXXXX");
puts(s2);

could print either "hello" or "XXXXX".

Or, since its behavior is undefined, it could print "YYYYY", or
"Good-bye, cruel world", or do anything else.
 
K

Keith Thompson

pete said:
Keith Thompson wrote: [...]
It's even permitted (though unlikely) for an implementation to store
string literals in writable memory, but to share the same memory for
multiple instances of the same literal. Thus this code fragment:

char *s1 = "hello";
char *s2 = "hello";
strcpy(s1, "XXXXX");
puts(s2);

could print either "hello" or "XXXXX".

More interestingly, I think,
at that point in the code, even
puts("hello");
could print either "hello" or "XXXXX".

Or "Ouch!", or e-mail a resignation letter to your boss, or ....

Yes, that's a better example.
 

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,773
Messages
2,569,594
Members
45,123
Latest member
Layne6498
Top