【问题标题】:What implementation of getenv is used if no header is included?如果不包含标头,则使用 getenv 的什么实现?
【发布时间】:2019-07-15 04:40:57
【问题描述】:

我正在开发一个用于学习目的的简单程序,我看到以下行为:

如果我尝试使用 getenv 读取环境变量,它会按预期工作:

#include <stdio.h>
#include <stdlib.h> 

int main() {
    printf("PATH is %s", getenv("PATH"));
    return 0;
}

如果我不包含 stdlib.h,我会收到预期的警告:

env.c:7:26: warning: implicit declaration of function ‘getenv’; did you mean ‘getline’? [-Wimplicit-function-declaration]

程序仍在编译。运行带有标头的程序按预期运行,不包含标头的程序会出现段错误。

如果我检查这两个程序的反汇编,我发现有一个调用 getenv@PLT

call    getenv@PLT

当我输出 2 个程序的反汇编时(c 源代码中唯一的区别是头文件包含),我看到的唯一区别是,当我们包含头文件时,有一条指令将 %eax 之前设置为 0调用 getenv。

movl    $0, %eax

如果我在 gdb 中单步执行没有包含标头的程序,它会跳转到 getenv 并在 c 运行时运行大量代码。

我想知道为什么不在这里包含标题会导致这种行为的确切原因是什么?为什么 c 让这个编译?

一些信息: gcc 版本 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1) 我是这样编译的: gcc -O0 -S 环境.c

【问题讨论】:

  • 试试gcc -Wall -Wextra -pedantic
  • 它假定函数返回一个int 并误解了结果。不要这样做。
  • 为什么不把生成的汇编代码贴在这里?
  • 如果您正在编译 64 位,这是因为 int 和指针具有不同的大小,并且返回指针的未声明的 getenv 被视为返回 int。但即使在这种情况下,汇编代码也应该有其他区别,而不仅仅是将 eax 设置为零;在printf 调用之前压入堆栈的参数应该有所不同。

标签: c


【解决方案1】:

在 C 语言中,如果您忘记包含头文件,getenv() 函数将被解释为int getenv(...)。如果包含头文件,getenv() 函数将被解释为char* getenv(const char*)。由于printf() 的实现,您的情况的唯一区别是返回值的大小。如果sizeof(int) == sizeof(char*),那么您没有问题(这发生在 32 位程序中)。如果sizeof(int) != sizeof(char*),您会收到一个错误(这发生在 64 位程序中)。这在评论#5中进行了解释

【讨论】:

  • 您不会总是在 64 位上遇到错误,这使得这更加阴险。
  • 我同意你的看法
猜你喜欢
  • 1970-01-01
  • 2011-10-05
  • 1970-01-01
  • 1970-01-01
  • 2012-11-07
  • 1970-01-01
  • 2021-06-08
  • 1970-01-01
  • 2010-12-13
相关资源
最近更新 更多