问题
I am learning the C programming language and am running into difficulties in understanding the minute differences between pointers, arrays and read only memory. I am working with the following example:
char *myCards = "JQK";
From what I understand what this line of code accomplishes is it creates a null terminated string of characters in a read only section of memory that is accessible via the char pointer myCards. This means that I am able to compile the following but would receive an error due to the immutability of the string:
*myCards = 'A';
I am trying to achieve a similar functionality using an array of ints; however, I am not at all certain on how to create this array and place it in a read only section of memory if at all possible.
I know that I can use the const keyword and create an array as follows:
const int myInts[] = {3, 6, 1, 2, 3, 8, 4, 1, 7, 2};
However, I am able to do the following, directly after this array initialization:
printf("First element of array: %i\n", myInts[0]);
int *myIntsPtr = myInts;
*myIntsPtr = 15;
printf("First element of array: %i\n", myInts[0]);
I was able to alter the first element of the array by creating a pointer to it, implying that this array was never placed into read only memory.
Basically I am stuck on trying to figure out how I am able to declare this int array so that it is in read only memory similar to "JQK". Any insight is helpful. Thank you.
回答1:
Ok, first to understand this, it's important to know that const in C doesn't have to do anything with read-only memory. For C, there is no such thing as sections. const is merely a contract, it's expressing the intention that something is indeed constant. This means a compiler/linker can place data in a read-only section because the programmer assured it won't change. It doesn't have to, though.
Second, a string literal translates to a constant array of chars with 0 implicitly appended. See Peter Schneider's comment here: it is not formally const (so the compiler won't warn you when you take a non-const pointer to it), but it should be.
Combining this, the following code segfaults on my system with gcc on Linux amd64, because gcc indeed places the array in a read-only section:
#include <stdio.h>
const int myInts[] = {3, 6, 1, 2, 3, 8, 4, 1, 7, 2};
int main(void)
{
printf("First element of array: %i\n", myInts[0]);
int *myIntsPtr = myInts;
*myIntsPtr = *(myIntsPtr + 1);
printf("First element of array: %i\n", myInts[0]);
return 0;
}
Note there is also a compiler warning in the line where you take a non-const pointer to the const array.
Btw, the same code will work if you declare the array inside your function with gcc, that's because then, the array itself is created on the stack. Still you get the warning, the code is still wrong. It's a technical detail of how C is implemented here. The difference to a string literal is that it is an anonymous object (the char array doesn't have an identifier) and has static storage duration in any case.
edit to explain what a string literal does: The following codes are equivalent:
int main(void)
{
const char *foo = "bar";
}
and
const char ihavenoname_1[] = {'b', 'a', 'r', 0};
int main(void)
{
const char *foo = ihavenoname_1;
}
So, short story, if you want gcc to put data in a read-only section, declare it const with static storage duration (outside of a function). Other compilers might behave differently.
回答2:
I do agree with Felix Palmen. An array within a function is stored on the stack, even if it is const, and you can modify it with the appropriate cast. Here is what I've got with MS-VC++ (ebp is the stack pointer):
const int test [ 5 ] = { 0, 1, 2, 3, 4 };
00309598 mov dword ptr [ebp-1Ch],0
0030959F mov dword ptr [ebp-18h],1
003095A6 mov dword ptr [ebp-14h],2
003095AD mov dword ptr [ebp-10h],3
003095B4 mov dword ptr [ebp-0Ch],4
( ( int* ) test ) [ 1 ] = 0;
003095BB mov dword ptr [ebp-18h],0
Now, defining the array within the function, but as static const this time, or defining it as a const global variable... We have the same result for both tests: the array is now in the data segment (usage of an address rather than ebp) but can still be modified:
static const int test [ 5 ] = { 0, 1, 2, 3, 4 };
( ( int* ) test ) [ 1 ] = 0;
01449598 mov dword ptr [test+4 (145ECACh)],0
With gcc you will have data in a read-only memory, but as Felix said, it is not garanteed: If you use MS-VC, for instance, you can still modify it.
来源:https://stackoverflow.com/questions/33056598/pointers-arrays-and-read-only-memory-in-c