【问题标题】:Discards qualifiers with memcpy使用 memcpy 丢弃限定符
【发布时间】:2015-07-14 13:59:13
【问题描述】:

为什么下面的代码会给我一个“丢弃限定符”警告?

double* const a[7];
memcpy(a,b,sizeof(double*)*7);

我在使用 Apple LLVM 6.1.0 版 (clang-602.0.53)(基于 LLVM 3.6.0svn)时遇到的错误是

warning: passing 'double *const [7]' to parameter of type 'void *' discards qualifiers

编辑:

奖金问题。为什么restrict关键字也不起作用?

double* restrict a[7];
memcpy(a,b,sizeof(double*)*7);

编辑 2:

我问这个问题,因为我希望 a 成为 const restrict 指针。我可以用这段代码得到这个结果:

double* const restrict a[7] = {b[0], b[2], ... b[7]};

这是一件愚蠢的事情吗?

【问题讨论】:

    标签: c c99


    【解决方案1】:

    您正在尝试将 const 指针传递给需要非 const 指针的函数。

    编辑:

    更具体地说,a 是一个数组,其内容是 const 指向双精度数的指针。如果您尝试执行a[0] = b[0](假设b 定义为double *b[7] 或类似的东西),您将收到编译器错误。如果您有const char a[7] 并尝试a[0] = 'x',结果将是相同的。

    按您的身份调用memcpy 可以使其有效地执行上述操作,否则会被禁止。

    restrict 的情况下,它告诉编译器给定指针指向的内存只能由给定指针寻址。这允许编译器执行某些优化。

    来自Wikipedia

    它表示对于指针的生命周期,只有它或一个值 直接从它派生(如指针+1)将用于访问 它指向的对象。

    由于 memcpy 不期望 restrict * 保证丢失,这就是您收到警告的原因。一般来说,像这样绕过restrict 会导致不可预知的行为。

    【讨论】:

    • 谢谢。我现在在文档中看到它。但是为什么 memcpy 需要一个非常量指针呢?它不应该只是复制一些东西到地址而不对地址本身做任何事情吗?
    • 这并不能真正回答问题,而是改写错误消息。
    • @hanno:历史。 C最近才获得const
    • @LightnessRacesinOrbit 奇怪的是,它在第​​二个参数(源)中包含 const 关键字(用于数据,而不是指针)。我还是不明白其中的逻辑。
    • @hanno:根据其定义,memcpy 写入目标位置,而仅从源位置读取。在第二个参数中添加const 进一步强调了这一点。
    【解决方案2】:

    因为a 是常量。

    double* const a[7]; 是一个包含 7 个指向 double 的指针的数组。这个数组(!,而不是指向的双精度数)被标记为 const。 memcpy 的第一个参数是目标,它不是 const(因此可以写入)。因此,不允许将 const a 作为非 const 目标传递给 memcpy。

    【讨论】:

      【解决方案3】:

      memcpy 接受三个参数。第一个参数是将数据复制到的位置。由于指针指向的位置将被修改,因此无论指针指向什么,都必须为常量,以避免潜在的未定义行为。

      由于您将aconst 指针)作为第一个参数传递,因此您会收到警告。

      请注意,第二个参数可以指向const 位置,因为数据是从中读取的。

      函数的签名如下:

      void* memcpy(void* dest, const void* src, size_t count);
      

      【讨论】:

        【解决方案4】:

        在本次通话中

        memcpy(a,b,sizeof(double*)*7);
        

        下面的方法可以写得更简单

        memcpy( a, b, sizeof( a ) );
        

        函数memcpy 更改数组a 的元素,因为它将数组b 的元素复制到数组a 的元素中。

        但是数组a 的声明如下所示

        const T a[7];
        

        T 可以这样定义

        typedef double * T;
        

        也就是说,您正在尝试更改常量数组,编译器会警告您此操作具有未定义的行为。

        我怀疑你的意思可能是另一个数组 a 的声明,例如

        const double * a[7];
        

        在这种情况下,您可以使用函数memcpy 的调用。

        【讨论】:

        • 不是。您不会收到“尝试更改常量数组”的警告。如果它通过const 对象,你会得到一个错误,否则只有UB。警告是针对尝试从类型中隐式丢弃 constness。
        • @Lightness Races in Orbit 到目前为止,我认为移除 constness 意味着您正在尝试更改常量对象。:)
        猜你喜欢
        • 1970-01-01
        • 2014-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多