c库函数getenv引起的core dumped

24 Sep 2016 c库函数getenv引起的core dumped

最近的项目中使用c作为开发语言,由于我之前学习c仅限于看完了几本相关书籍,除了上学期间和找工作时写的一些c程序以及工作中一些关于c的bug fix,在项目中使用c还是第一次,通过这段时间对c的使用,更能体会到下面这句话的含义:

如果没有真正骑过自行车,就算看十本教你学骑自行车的书,最后还是不会骑自行车

其实意思就是学习编程语言,只看书还是不行的(当然不看书也不行)。也正是由于我实践经验少,在使用c库函数getenv()获取系统环境变量时,由于使用不当导致Segmentation fault (core dumped)错误。当时想不通为什么如此简单的库函数怎么就会引起core dumped呢?感兴趣可以看看,代码如下:

#include <stdio.h>
int main ()
{
    char *p = getenv("PATH");
    printf("%s\n", p);
    return 0;
}

编译运行如下:

root@leo:demo# gcc getenv.c -o getenv && ./getenv
getenv.c: In function ‘main’:
getenv.c:4:12: warning: initialization makes pointer from integer without a cast [enabled by default]
  char *p = getenv("PATH");
            ^
Segmentation fault (core dumped)

其实如果仔细看gcc编译时的警告信息,就应该马上知道问题出在什么地方。我偏觉得一个如此简单的程序,有警告也可以忽略,不看也罢。然后我想了好久,就是想不通为啥会导致core dumped。于是先man一下这个函数,解释如下:

GETENV(3)                                Linux Programmer's Manual                                GETENV(3)

NAME
       getenv, secure_getenv - get an environment variable

SYNOPSIS
       #include <stdlib.h>

       char *getenv(const char *name);

       char *secure_getenv(const char *name);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       secure_getenv(): _GNU_SOURCE

DESCRIPTION
       The  getenv()  function  searches  the  environment  list to find the environment variable name, and
       returns a pointer to the corresponding value string.

RETURN VALUE
       The  getenv()  function  returns  a  pointer to the value in the environment, or NULL if there is no
       match.

通过使用文档,可以了解到getenv()函数主要功能是在系统的环境变量列表中查找参数name指定的环境变量。如果找到相应的环境变量,那么返回一个指向该环境变量值的字符串指针。如果没有找到,返回NULL。原谅我的智商,看完这个解释我还是没明白为什么我的代码会core dumped。直到我打开浏览器,谷歌了一下,然后看到http://stackoverflow.com/上也有人问同样的问题,问题链接如下:

http://stackoverflow.com/questions/27348009/getenv-segmentation-fault

看完别人的解答,我当时想说牛话,还好忍住了,原来是因为没有添加头文件#include <stdlib.h>,我又想,没有添加头文件为什么能编译过。这就是gcc在搞鬼了,因为gcc提供了一些内置函数,如果在代码中没有添加相应函数的头文件,那么gcc会使用内置函数,所以能编译通过。但是由于函数没有提供头文件,即没有声明,默认返回值是int型。其实问题就出在这里,因为getenv()没有声明,它返回的整数被当成一个地址使用,但是由于这个地址是一个不可访问的地址,所以访问该地址就会导致core dumped,到此,问题解决。

正确代码如下:

#include <stdio.h>
#include <stdlib.h>
int main ()
{
    char *p = getenv("PATH");
    printf("%s\n", p);
    return 0;
}

编译运行如下:

root@leo:demo# gcc getenv.c -o getenv && ./getenv
/opt/python-2.7.10/bin:/root/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

总结

  • c函数使用前必须声明,不然默认返回值是int
  • 不要忽略编译时的警告信息,有时候bug fix的提示信息就在里面
  • 遇到问题一定要搞明白,不然下次还是不明白(这个是同事兼球友祁大神经常说的)
  • 学编程实践很重要(大道理大家都懂Orz)

本次荐书:黑客与画家

LEo at 20:21

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Crossin的编程教室

一些常见的新手问题

本账号开设至今,回答的各种问题,没有一万也有八千了。今天挑了其中曝光率较高的一些问题,跟各位分享,供入门不久和新关注的同学参考。 1. 我是零基础,如何开始学习...

31290
来自专栏企鹅号快讯

用functools.lru_cache实现Python的Memoization

用functools.lru_cache实现Python的Memoization 现在你已经看到了如何自己实现一个memoization函数,我会告诉你,你可以...

26490
来自专栏coding for love

JS常用设计模式解析02-策略模式

在于都本文之前,希望大家能够先阅读以下JS进阶系列03-JS面向对象的三大特征之多态这篇文章,了解JS的多态。在这篇文章,我们举了一个例子,就是选拔官员选拔合唱...

13730
来自专栏游戏杂谈

php正则表达式的分组捕获

经过测试,发现php正则表达式获取分组捕获是从$0开始,而平时工作中JavaScript中的正则是$1..$9

16930
来自专栏码洞

深入理解 RPC 消息协议设计

本节我们开始讲解 RPC 的消息协议设计背后的基本原理,了解 RPC 的协议开发背后有哪些需要考虑的基本点。在通晓原理之后,我们就可以自己设计一套协议来开发属于...

14930
来自专栏Ldpe2G的个人博客

ScalaMP ---- 模仿 OpenMp 的一个简单并行计算框架

11730
来自专栏性能与架构

Redis 新数据结构 - Streams

1. 为什么添加 Streams 数据流? Stream 数据流的使用越来越多,Redis 的作者 antirez 也在积极思考,如何让 redis 能够很好的...

43360
来自专栏数据小魔方

左手用R右手Python系列16——XPath与网页解析库

最近写了不少关于网页数据抓取的内容,大多涉及的是网页请求方面的,无论是传统的RCurl还是新锐大杀器httr,这两个包是R语言中最为主流的网页请求库。 但是整个...

35550
来自专栏鹅厂优文

深入浅出Lua虚拟机

本文标题是”深入浅出 Lua 虚拟机”,其实重点在浅出这两字上。毕竟作者的技术水平有限。但是听说名字要起的屌一点文章才有人看,故而得名。

1.4K140
来自专栏偏前端工程师的驿站

JS魔法堂:函数节流(throttle)与函数去抖(debounce)

一、前言                                     以下场景往往由于事件频繁被触发,因而频繁执行DOM操作、资源加载等重行为,导致...

25860

扫码关注云+社区

领取腾讯云代金券