测试平台: 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/articles/3819233.html
(adsbygoogle = window.adsbygoogle || []).push({});