Pointers Arrays and Read Only Memory in C

烈酒焚心 提交于 2019-12-06 08:36:48

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!