【问题标题】:Executable not running可执行文件未运行
【发布时间】:2017-03-15 09:19:28
【问题描述】:

我有以下代码:

# include<stdio.h>
# include<string.h>
# define M 5 

void mycopy(char* text)
{
     char buffer[M];
     strcpy(buffer, text);
}

int main()
{
    char *name = "Kshitij";
    int i = 0;
    mycopy(name);
    printf("i = %d", i);
    return 0;
}

此代码在 Apple LLVM 版本 8.0.0 (clang-800.0.42.1) 上的 GCC 中编译。 但是,当我尝试运行相应的可执行文件时,我得到一个进程abort 输出,例如:

[1]    PID abort     ./executable.out

我知道会出现错误,因为在这种情况下,buffer 数组的大小小于传递给它的 text 参数的长度。但是,我无法理解掌握这种行为背后的概念。为什么这里没有说明编译器引发的原因的编译时错误?

【问题讨论】:

  • C 编译器不会评估/触发数组的越界错误。运行时您的代码调用UB。在您的情况下,您可能正在破坏堆栈并返回 main 失败。
  • 如果您不想在编程时担心这些细节,那么您可能应该选择 C ​​以外的语言。
  • 你是说编译器应该检测到你正在strcpy从一个参数进入mycopy中大小为5的缓冲区,并在你传递一个包含变量的参数时告诉你指向大于该字符串文字的指针并发出警告?我想这是可能的。但是,它并没有真正有用到经常存在。
  • 研究编译时错误和运行时错误的区别。我认为一些高级编译器可能会在警告级别保持较高时提供这种情况作为警告,但总的来说,从 C 编译器的角度来看,这不是任何语法错误。
  • @LPs 感谢您分享有关“未定义行为”的信息。在我的主要编码课程中,我从未被介绍过。

标签: c compiler-errors compilation runtime-error


【解决方案1】:

C11 标准在7.1.4. Use of library functions 中说:

如果函数参数被描述为一个数组,*实际传递给函数的指针具有一个值,使得所有地址计算和访问到对象(如果指针确实指向此类数组的第一个元素,那将是有效的)实际上是有效的。

strcpy

2 strcpy函数将s2指向的字符串(包括终止空字符)复制到s1指向的数组中。

Appendix J.2 Undefined behavior:

1 在以下情况下行为未定义: 传递给库函数数组参数的指针不具有使所有地址计算和对象访问都有效的值 (7.1.4)。

由于行为是未定义的,根据标准,任何事情都可能发生。编译器实际上允许进行编译时边界检查,如果可以推断出程序总是写越界,那么编译很可能会中止。或者,实现可以支持范围检查并通过明确的诊断中止。或者 strcpy 可能只是复制前 4 个字符并添加终止 null,或者将 42 复制到目标字符串中 - 所有这些实现都将符合标准。

【讨论】:

    猜你喜欢
    • 2011-12-08
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-07-10
    • 2020-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多