专栏首页Pulsar-VC/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/articles/3819233.html

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • OpenMPI 目录切换指令 原

    OpenMPI的程序运行必须保持相同的目录,默认情况下,MPI的分布式节点会去~/user目录下面寻找运行的程序,如果找不到该程序,则会报出

    Pulsar-V
  • Python-四元数类

    Pulsar-V
  • SLAM初探(四)

    OpenCV基础 这里我就不做过多的描述性问题,现在OpenCV在许多有关计算机视觉方面得到许多的应用。 OpenCV获取视频的方法及其图像转化问题 获取视频及...

    Pulsar-V
  • python内置模块之string

    str.capitalize() 把字符串的第一个字符大写 str.center(width) 返回一个原字符串居中,并使用空格填充到width长度的...

    菲宇
  • Javascript字符串常用方法详解

    => 返回字符串的第 n 个字符,如果不在 0~str.length-1之间,则返回一个空字符串。

    前端博客 : alili.tech
  • 去除字符数组中指定的字符

    Winter_world
  • 5.QT-QString类

    张诺谦
  • C#字符串截取

    yaphetsfang
  • [剑指offer] 字符串的排列

    输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,c...

    尾尾部落
  • LeetCode 709. 转换成小写字母

    实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。

    Michael阿明

扫码关注云+社区

领取腾讯云代金券