1. 程式人生 > >C/C++踩坑記錄(二)一段有趣的常量字串

C/C++踩坑記錄(二)一段有趣的常量字串

測試平臺:
Ubuntu 16.04
Windows Mingw GCC gcc version 5.3.0 (i686-posix-dwarf-rev0, Built by MinGW-W64 project)

編譯器:GCC 5.3
開始不得不吐槽一下網上那些所謂“C語言字串翻轉”的實現的哥們啊,我看到他們程式碼#include<iostream>和引入STL的時候我都不知道我是該哭還是該笑。
好吧我們開始,從一個簡單的問題去分析問題。
先貼程式碼: 這是我實現的:

#include <stdio.h>

void s_reverse(char *s) {
    char *h = s;
    char *t = s;
    char ch;
    /* t指向s的尾部 */
    while (*t++) {};
    t--;    /* 與t++抵消 */
    t--;    /* 回跳過結束符'\0' */
    /* 當h和t未重合時,交換它們所指向的字元 */
    while (h < t) {
        ch = *h;
        *h++ = *t;    /* h向尾部移動 */
        *t-- = ch;    /* t向頭部移動 */
    }
}

int main() {
    char str[] = {'H','e','l','l','o','\0'};//為啥分成兩個後面說
    char *str_1 = "Hello, World!";
    printf("origin str ---> %s\n",str);
    printf("origin str_1 ---> %s\n",str_1);
    s_reverse(str);
    s_reverse(str_1);
#ifdef _MSC_VER
    printf("%s\n", str, "Visual Stadio 2017");
    printf("str--->%s\n",str);
    printf("str_1--->%s\n",str_1);
#else
    printf("str--->%s\n",str);
    printf("str_1--->%s\n",str_1);
#endif
    return 0;
}

這是自帶的:

#include <string.h>
int main() {
    char *str ="Hello, World!";
    strrev(str);
    return 0;
}

只關注str_1現在分別來看看它們在Mingw下的表現(注:這裡Mingw下的效果和Linux測試一致)和MSVC下的表現
MyCode on Mingw

MyCode on MSVC

Official on Mingw

Official on MSVC

那麼GCC下的報錯問題出在哪呢
追根溯源才是人類的本質,現在生成一下GCC的彙編程式碼,看看到底發生了什麼。

gcc  ./main.c -S
gcc  ./str.c -S

現在分別生成了兩份程式碼 main.s裡面我們可以看到這麼一段

LC0:
	.ascii "Hello, World!\0"

是的這玩意被定義為常量了,無法被訪問
使用陣列形式宣告字串

char str[] = {'H','e','l','l','o','\0'};

然後我們註釋掉str_1相關的東西再來看看str。

Any thin look like good.
現在再來生成彙編程式碼,我們能看到ascii不見了,所有的東西都在棧上,變成了可以訪問的變數。 雖然已經找到問題所在,下面我們來除錯一下丟擲異常的地方。。

由於str.s的程式碼只是call _strrev,所以我們根據他的原型,用上面自己實現的程式碼去尋找問題根源。

gdb main.exe


設定斷點

break s_reverse

按下r執行

通過disassemble命令來檢視彙編程式碼
彙編步進除錯ni

慢慢的除錯過去,會發現

mov    %dl,(%eax)

這句話的意思是從資料暫存器DX低位取資料放到eax中,但是此時資料暫存器是不可寫的,所以丟擲了異常中斷

參考文獻:
[DWARF4]http://dwarfstd.org/doc/DWARF4.pdf

[.cfi指令解讀]https://blog.csdn.net/jtli_embeddedcv/article/details/9321253

[劍指offer]
[彙編中的暫存器]https://www.cnblogs.com/wisehead/arti