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

The above snippet will generate "warning: cast discards ‘__attribute__((const))’ qualifier from pointer target type [-Wcast-qual]". I like -Wcast-qual since it can help me from accidentally writing to memory I shouldn't write to.

But now I want to cast away const for only a single occurrence (not for the entire file or project). The memory it is pointing to is writable (just like buf above). I'd rather not drop const from ptr since it is used elsewhere and keeping to pointers (one const and one non-const) seems like a worse idea.

ext
  • 2,593
  • 4
  • 32
  • 45
  • 1
    Why not just `char *q = buf;` ? – Paul R Nov 06 '12 at 11:12
  • I guess thats unclear from the snippet, I perform arithmetic on ptr before the cast. – ext Nov 06 '12 at 11:14
  • 1
    It might be better to use an index into buff rather than manipulating pointers then, and pass e.g. `&buff[i]` instead of a pointer ? – Paul R Nov 06 '12 at 11:17
  • While the approach requires changes in existing code it appears to be the way to go. I was hoping for some attribute or keyword to say "hey I know what I'm doing, ignore this" like you can do with unused variables. – ext Nov 06 '12 at 13:49
  • A very similar warning is `-Wwrite-strings` which gcc 4.8 was reporting as `error: initialization discards 'const' qualifier from pointer target type [-Werror]`. Unfortunately `-Wno-error=write-strings` was ignored with this version. – jozxyqk Sep 05 '18 at 23:13

4 Answers4

9
#include <stdint.h>

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

Or, without stdint.h:

char *  p = (char *)(unsigned long)ptr;
Bruce K
  • 749
  • 5
  • 15
  • 1
    I would discourage this approach. Don't work around the warnings. If you don't want them, use suppressions, which is what they are meant for. This will be explicit about your intentions and make your code much more readable. – André Fratelli Sep 06 '16 at 13:06
  • 4
    Suppressions are not generally portable. And if you share your code, someone will compile with something that hates your suppression method. If you want to be explicit: #define UN_CONSTIFY(_t, _v) ((_t)(uintptr_t)(_v)) – Bruce K Jun 08 '17 at 21:00
  • Shouldn't it be `char * p = (char *)(void *)(uintptr_t)(void *)ptr;` instead of `char * p = (char *)(uintptr_t)ptr;`? AFAIK [a conversion to void * is required before converting a pointer to uintptr_t](https://stackoverflow.com/questions/45352226/is-a-conversion-to-void-required-before-converting-a-pointer-to-uintptr-t) – David Ranieri Oct 02 '21 at 09:08
6

In GCC 4.2 and later, you can suppress the warning for a function by using #pragma. The disadvantage is you have to suppress the warning across the whole function; you cannot just use it only for some lines of code.

#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

The advantage is your whole project can use the same warning/errors checking options. And you do know exactly what the code does, and just make GCC to ignore some explicit checking for a piece of code.
Because the limitation of this pragma, you have to extract essential code from current function to new one, and make the new function alone with this #pragma.

jclin
  • 2,449
  • 1
  • 21
  • 27
  • 4
    **Enabled by default warnings: The GNU compiler collection (GCC) 4.6.3 might generate enabled by default warnings that cannot be suppressed.** `-Wcast-qual` is one of them: `warning: initialization discards ‘const’ qualifier from pointer target type **[enabled by default]**` – David Ranieri Aug 06 '13 at 08:50
  • 2
    @AlterMann: That's a completely different warning that occurs when you make an **implicit** conversion which discards the `const` qualifier (which is invalid C; C does not have such an implicit conversion). It's not the warning OP is seeing. – R.. GitHub STOP HELPING ICE Jul 18 '14 at 18:37
0

As long as you are fine with GCC/clang specific code then this should do the job:

#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);

Alternatively, a modified version based on Is cast of pointer to anonymous union valid in C11?:

#define CONST_CAST2(TOTYPE,FROMTYPE,X) ((union {FROMTYPE _q; TOTYPE _nq;}){._q=constBoo}._nq)
Filip Navara
  • 4,818
  • 1
  • 26
  • 37
-1

Bit late, but you can also do this without mucking with warnings at all:

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

You end up with q = buf + ptr - buf = ptr + buf - buf = ptr, but with buf's constness.

(Yes, this allows you to remove const from any pointer at all; const is advisory, not a security mechanism.)

David X
  • 3,998
  • 3
  • 29
  • 32