2009年7月30日 星期四

C 的字串...char* 和 char[]

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

typedef struct {
    char name[20];
    long id;
    long long salary;
} Personal1;

typedef struct {
    char *name;
    long id;
    long long salary;
} Personal2;

Personal1 p1={"Charlie", 1l, 45000l};
Personal2 p2={"Richard", 2l, 45000l};

int main(void)
{
    printf("name:%s id:%ld salary:%ld\n", p1.name, p1.id, p1.salary);
    printf("name:%s id:%ld salary:%ld\n", p2.name, p2.id, p2.salary);

    strcpy(p1.name, "test1");
    //strcpy(p2.name, "test2");  //這行可以compiler過,不過程式執行會當在這

    printf("name:%s id:%ld salary:%ld\n", p1.name, p1.id, p1.salary);
    printf("name:%s id:%ld salary:%ld\n", p2.name, p2.id, p2.salary);

    return 0;
}


首先,這程式有個錯誤的理解,就是在宣告p1.p2同時填入struct裡的內容時,p2的填入過程會填錯...意思是name.id及salary會互相覆蓋之類的...
不過結果不會也,compiler會很聰明的配置一塊區域,給name,然後指向它,其它就正確的填入應該的位置...
接下來又發生一個問題,就是註解掉的那一行,雖然可以編譯通過,不過執行時,會發生Access violation的錯誤....
猜測,這代表編譯器會配置空間放字串,不過是放在唯讀區域

另外又讓我弄了一個實驗,程式如下:
#include <stdio.h>

char test1[]="Charlie";
char *test2="Richard";

int main(void)
{
    printf("%s\n",test1);
    printf("%s\n",test2);
    strcpy(test1,"test1");
    //strcpy(test2,"test2");  //這行可以compiler過,不過程式執行會當在這
    printf("%s\n",test1);
    printf("%s\n",test2);
    return 0;
}

現在我們知道,這兩種預宣告字串內容的方法,對於compiler配置的方法是不同的...

char test1[]="Charlie"; 配置剛好的記憶體空間,並且從literal constant區域複製字串內容過來,而test1只是個常數,代表這個配置空間的第一個位置

char *test2="Richard"; 配置一個指標變數,並且複製literal constant區域內某字串的第一個位置值,所以*test2指向literal constant這個區域,由於唯讀,所以對其修改會產生Access violuation....

另外這些區域的保護作用,也不是編譯器說了算,是要OS(認出來做處裡)和CPU(的機制)互相配合,才可以實現....
若是某些embedded system的情境下,有可能是literal constant的區域(section)是放在唯讀記憶體(或flash),所以無法寫入,或者寫也寫不進,如果經過適當的處理(Relocate 和適當的搬移),把literal constant區域複製到RAM上,則存取就沒問題了

相關連結:
http://twpug.net/docs/ccfaq/node16.html#q:1.32
http://www.yuanma.org/data/2007/0305/article_2375.htm
http://birdegg.wordpress.com/2006/10/21/re-問題-cc中char與char的差異/

沒有留言:

張貼留言