【问题标题】:Explicit ignore warning from -Wcast-qual: cast discards ‘__attribute__((const))’ qualifier from pointer target type来自 -Wcast-qual 的显式忽略警告:cast 从指针目标类型中丢弃“__attribute__((const))”限定符
【发布时间】:2023-03-18 09:16:02
【问题描述】:
static char buf[8];
void foo(){
    const char* ptr = buf;
    /* ... */
    char* q = (char*)ptr;
}

上面的sn-p会生成"warning: cast discards ‘__attribute__((const))’ qualifier from pointer target type [-Wcast-qual]"。我喜欢-Wcast-qual,因为它可以帮助我避免意外写入我不应该写入的内存。

但现在我只想抛弃 const 一次(而不是整个文件或项目)。它指向的内存是可写的(就像上面的buf)。我宁愿不要从 ptr 中删除 const,因为它在其他地方使用并且保持指针(一个 const 和一个非常量)似乎是一个更糟糕的主意。

【问题讨论】:

  • 为什么不直接char *q = buf;
  • 我猜这从 sn-p 中不清楚,我在演员表之前对 ptr 执行算术。
  • 最好使用 buff 的索引而不是操作指针,然后传递例如&buff[i] 而不是指针?
  • 虽然该方法需要更改现有代码,但它似乎是可行的方法。我希望某个属性或关键字可以说“嘿,我知道我在做什么,忽略这个”,就像你可以对未使用的变量做的那样。
  • 一个非常相似的警告是-Wwrite-strings,gcc 4.8 报告为error: initialization discards 'const' qualifier from pointer target type [-Werror]。不幸的是,此版本忽略了 -Wno-error=write-strings

标签: c gcc warnings


【解决方案1】:
#include <stdint.h>

const char * ptr = buf;
....
char * p = (char *)(uintptr_t)ptr;

或者,没有 stdint.h:

char *  p = (char *)(unsigned long)ptr;

【讨论】:

  • 我不鼓励这种方法。不要绕过警告。如果您不想要它们,请使用抑制,这就是它们的目的。这将明确您的意图并使您的代码更具可读性。
  • 抑制通常不可移植。如果你分享你的代码,有人会用讨厌你的抑制方法的东西来编译。如果你想明确:#define UN_CONSTIFY(_t, _v) ((_t)(uintptr_t)(_v))
  • 不应该是char * p = (char *)(void *)(uintptr_t)(void *)ptr;而不是char * p = (char *)(uintptr_t)ptr;吗? AFAIK a conversion to void * is required before converting a pointer to uintptr_t
【解决方案2】:

在 GCC 4.2 及更高版本中,您可以使用#pragma 来抑制函数的警告。缺点是您必须在整个函数中抑制警告;您不能只将它用于某些代码行。

#pragma GCC diagnostic push  // require GCC 4.6
#pragma GCC diagnostic ignored "-Wcast-qual"
void foo(){
    const char* ptr = buf;
    /* ... */
    char* q = (char*)ptr;
}
#pragma GCC diagnostic pop   // require GCC 4.6

优点是您的整个项目可以使用相同的警告/错误检查选项。而且您确实知道代码的作用,只是让 GCC 忽略对一段代码的一些显式检查。
由于这个 pragma 的限制,你必须从当前函数中提取必要的代码到新函数中,并用这个#pragma 单独制作新函数。

【讨论】:

  • 默认启用警告:GNU 编译器集合 (GCC) 4.6.3 可能会生成默认启用无法抑制的警告。 -Wcast-qual 是其中之一:@ 987654323@
  • @AlterMann:这是一个完全不同的警告,当您进行 implicit 转换时会丢弃 const 限定符(这是无效的 C;C 没有这样的隐式转换)。这不是 OP 看到的警告。
【解决方案3】:

只要您对 GCC/clang 特定代码没问题,那么 this 应该可以完成这项工作:

#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
#define CONST_CAST(TYPE,X) CONST_CAST2 (TYPE, const TYPE, (X))

const char *ptr = buf;
char *q = CONST_CAST(char *, ptr);

或者,基于Is cast of pointer to anonymous union valid in C11?的修改版本:

#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((union {FROMTYPE _q; TOTYPE _nq;}){._q=constBoo}._nq)

【讨论】:

    【解决方案4】:

    有点晚了,但你也可以这样做,而完全不用警告:

    static char buf[8];
    void foo(){
        const char* ptr = buf;
        /* ... */
        char* q = buf + (ptr-buf);
    }
    

    你最终会得到q = buf + ptr - buf = ptr + buf - buf = ptr,但会得到buf的常量。

    (是的,这允许您从任何指针中删除constconst 是建议性的,而不是安全机制。)

    【讨论】:

    • 警告仍然存在使用 gcc 4.7.2
    猜你喜欢
    • 2017-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-29
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多