【问题标题】:std::copy causes error without exceptionstd::copy 导致错误无一例外
【发布时间】:2015-08-24 07:52:01
【问题描述】:

我有这个代码来复制一个整数:

int parseInt(const char* data, unsigned int* ind) {
    int i;

    std::copy(&data[*ind], &data[*ind+sizeof(int)], &i); // i) STD::COPY
    // memcpy(&i, &data[*ind], sizeof(int)); // ii) MEMCPY
    std::cout << "--> " << i << std::endl;
    *ind += sizeof(int);
    std::cout << "OK" << std::endl;
    return i;
}

debian,此代码工作i) STD::COPY没有问题。

然后,我在embedded Arm上编译并运行了代码(sizeof(int)也是4)。 i) 的代码似乎也在运行,在函数中打印出预期的内容。

但是,从函数返回时会出现问题。

我也尝试过return 1; 而不是i,但还是一样。它不会抛出异常,也不会提供任何线索。我无法调试,因为我有限制,无法添加调试器。

只是在这个函数之后不再继续,即:

std::cout << "PARSING..." << std::endl;
parseInt(data, &ind);
std::cout << "PARSED!" << std::endl;
...

给出这个(值 11 是正确的):

PARSING...
--> 11
OK

然后进程冻结。

但是,当我使用 ii) MEMCPY 而不是 std::copy 时,代码可以正常工作。因此,在我看来问题是因为std::copy 而出现的。

有人知道这里会发生什么吗?

我是否错误地使用了std::copy?但是为什么它可以在 debian 桌面上运行,但不能在嵌入式 arm 上运行呢?

【问题讨论】:

  • 我不确定,但取消对过去指针的引用对我来说似乎很可疑。为什么不std::copy(data + *ind, data + *ind+sizeof(int), &amp;i)
  • @melak47 不一样?反正我试过了。但没有机会。

标签: c++ embedded-linux


【解决方案1】:
std::copy(&data[*ind], &data[*ind+sizeof(int)], &i);

这会将 sizeof(int) 字节复制到从 &amp;i 开始的 int 数组的连续元素,不用说这会导致未定义的行为,因为在 &amp;i 处没有数组。

你可能是说

std::copy(&data[*ind], &data[*ind+sizeof(int)], reinterpret_cast<char*>(&i));

memcpy 起作用的原因是因为它显式复制字节,std::copy 更通用,就像它在抽象迭代器上运行的其他标准算法一样,由你来确保你正确调用它。

【讨论】:

  • 只是为了好奇,这样的演员阵容是否违反了strict-aliasing规则?
  • @PaoloM 您始终可以使用char* 进行别名。
  • @MertMertce:因为我可以理解 memcpy() 行代码在做笔记时的作用。如果您所做的只是将原始字节从一个位置复制到另一个位置,std::copy() 不会给您带来太多好处。如果您要复制对象,也许std::copy() 是要走的路,但我在这里看不到太多优势。它读起来就像一场噩梦(至少是这个化身)。
  • @MichaelBurr 我可以看到支持memcpy 的论点,就我而言,我坚持使用copy,因为它具有其他算法的统一语法(即开始、结束、目的地/谓词) ,而演员的丑陋对于正在阅读“这里是龙”的人来说是一个明确的信号(尽管 OP 的索引不是我处理事情的方式)。在-O3 使用任何一种时,此示例生成的程序集都没有区别。
【解决方案2】:

std::copy 的文档:

 template <class InputIterator, class OutputIterator>   OutputIterator  
    copy (InputIterator first, InputIterator last, OutputIterator result);  

Copy range of elements Copies the elements in the range [first,last)
into the range beginning at result.

您正在使用 const char* 类型的输入迭代器。并且输出迭代器的类型是 int*。
复制函数从第一个到最后一个迭代,产生 4 次迭代。每次迭代在输入中每次推进一个字节。但是输出迭代器是 int* 类型的,所以每次迭代输出迭代器前进 4 个字节。这会导致您的 4 个输入字节被复制,每个输入字节之间间隔 3 个字节。
由于要接收该数据的元素是变量 i,它只能保存一个 int(4 个字节),这会导致未定义的行为,表现为在未指定的内存位置写入。很可能会覆盖 RET 指令返回到相应 CALL 所需的方向。
在 debian 中不会发生这样的事情取决于那里编译器的内存模型。你不能相信它是一致的。

在仍然使用 std::copy 的同时解决它的一种方法是使用 char* 迭代器作为输出迭代器:

char* ptrDest = reinterpret_cast<char*>(&i);
std::copy(&data[*ind], &data[*ind+sizeof(int)], ptrDest); // i) STD::COPY

【讨论】:

  • 已收到答复,但感谢您提供详细信息以及您愿意帮助 +1。
【解决方案3】:

您的 ARM CPU 可能不支持未对齐的内存访问。 memcpy 会为您处理这种情况。

【讨论】:

    猜你喜欢
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 2021-06-14
    • 1970-01-01
    相关资源
    最近更新 更多