【问题标题】:char array on stack causes seg fault [duplicate]堆栈上的字符数组导致段错误[重复]
【发布时间】:2015-07-14 20:43:54
【问题描述】:

这可能是意料之中的,但我只是好奇这是如何/为什么会发生的。

当我尝试使用在本地声明的 char * 作为整数时 char * foo = "\xFF\xFF..." 它会出现错误。但是,如果我使用 malloc ,当我尝试访问它时它工作得很好。为什么会这样?

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
  unsigned char *buf = malloc(16);
  memcpy(buf, "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 16);
  //unsigned char *buf = "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; // seg faults if you sue this instead

  uint64_t *k  = (uint64_t *) buf;
  uint64_t *k2 = (uint64_t *) (buf + 8);
  uint64_t i  = 1000000000;

  printf("-k =%" PRIu64 "\n", *k);
  printf("-k2=%" PRIu64 "\n", *k2);

  printf("Iter * %" PRIu64  "\n", i);
  for (uint64_t c = 0; c < i; ++c)
    {
      *k  += 1;
      *k2 -= 1;
    }

  printf("-k =%" PRIu64 "\n", *k);
  printf("-k2=%" PRIu64 "\n", *k2);

  return 0;

}

输出:

easytiger $ gcc -std=c99 tar.c -Wall -O2 ; time ./a.out
-k =0
-k2=18446744073709551615
Iter * 1000000000
-k =1000000000
-k2=18446744072709551615

【问题讨论】:

  • 你到底想做什么......?!?!为什么你的 C 问题被标记为c++
  • 即使字符串文字是可写的(它不是),由于对齐,代码在某些架构上可能会失败。
  • 一个错误。我只是看看会发生什么。它不适用于我正在编写的任何代码。
  • 只需使用unsigned char buf[] = "\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; ...如果仅在本地需要这几个字节,则无需malloc()

标签: c arrays malloc


【解决方案1】:

字符串字面量是不可变的。您不得修改存储在那里的数据。永远。

即使在现在的 C 语言中,我们也可以通过将 const 放入指针类型中来使这一点变得清晰和可诊断。

C++ 实际上需要它。

【讨论】:

  • +1 与您对下面 dbush 的评论相结合,是这里最彻底、最细致入微的答案,而不是过于简单化。
  • 我认为这个答案更准确地概述了其背后的机制:stackoverflow.com/questions/2589949/…(即.rodata)
  • @easytiger:我非常慎重地谈论某些特定编译器的实现细节/机制。这个问题是关于 C 的,这是一种高级编程语言,它根据定义抽象出这些细节。当您开始像那个答案那样沉迷于实现细节时,您会做出无法保证成立的假设和全面的陈述,尤其是面对所谓的“优化”(其中“优化”仅意味着“编译器在作者未能考虑的最佳方式”)。 :)
【解决方案2】:

无法保证字符串文字将存储在可写内存页中。这意味着 for 循环中的*k += 1 操作可能会尝试写入只读内存。另一方面,malloc 分配的内存将始终是可写的。

【讨论】:

    【解决方案3】:

    对于这种形式的定义:

    unsigned char *buf = "some string";
    

    buf 指向一个静态字符串,该字符串存储在内存的只读部分中。当您尝试写入时,您会遇到段错误。

    通过使用mallocbuf指向的内存是可写的。

    【讨论】:

    • 它可能不存储在只读内存中。而且它是否存在甚至都无关紧要:如果您希望程序具有明确定义的语义,该语言会禁止您改变字符串文字的组成字符。除此之外,对其进行合理化是没有意义的。
    • 谢谢,就这么简单。 Orbit 中的 Lightness Races 也是一个很好的观点。我猜 malloc 版本根本不像字符串文字那样对待。
    • 因为它不是文字。 (它是 memcpyd 的事实并不相关。)
    • 是的。您甚至可以开始谈论文字被优化掉的可能性以及其他等等等等,但没有必要。 :)
    • 嗯,这当然是吹毛求疵,但谈到语义,我希望能强制执行禁令;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-02
    • 2017-02-25
    • 2012-05-21
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多