1

I was deubugging a project written in C++ through GDB and discovered that a const was being modified without warning or error by the GNU C++ compiler.

This isn't the program I was debugging, but this is an example of the behavior I witnessed:

#include <iostream>

int main(int argc, char *argv[]) {
  const int x = 10;

  int *px = (int *)&x;
  ++*px;

  std::cout << "*px: " << *px << "\n";
  std::cout << "x: " << x << "\n";

  for (int i = 0; i < x; ++i)
    std::cout << i+1 << "\n";

  return 0;
}

I can't speak for other compilers because I only tested this with GNU C++ compiler, version 4.9.2. Why is something like this allowed? This breaks the entire point of const objects.

I compiled the above code with g++ main.c -Wall -Werror

The output:

*px: 11
x: 10
1
2
3
4
5
6
7
8
9
10
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
ffhaddad
  • 1,653
  • 13
  • 16

1 Answers1

5

As far as the compiler is concerned, you're not modifying a constant. You're modifying what a pointer to a non-const int points to, because that's what the cast (int *) tells the compiler to regard &x as.

This so-called C-style cast is the most powerful cast provided by C++. Casting should generally only be done to the extent that is really necessary. In many cases, const_cast, static_cast, or dynamic_cast suffice (there is also the quite powerful reinterpret_cast).

The behaviour of the C-style cast is to apply the least powerful cast that is required to allow compilation to succeed.

Dabbler
  • 9,733
  • 5
  • 41
  • 64
  • OK, I assumed this, but it seems like something like this should at least produce a warning. To go pass through the compiler silently is scary. – ffhaddad Jan 30 '15 at 19:13
  • It's basically C heritage, where such casting was common (in fact, originally, this was the only available method of casting, and it allowed pretty much anything). This is the reason for the introduction of the casts mentioned in my answer. The C-style cast is still around for backward-compatibility, but using it is not recommended. – Dabbler Jan 30 '15 at 19:15
  • 1
    @ffhaddad Another point of view: it normally doesn't go through the compiler silently. You'd normally get "error: invalid conversion from ‘const int*’ to ‘int*’". The cast tells the compiler "shut up, I know what I'm doing". –  Jan 30 '15 at 19:16
  • @Dabbler: Actually one may argue that the C-style cast is "necessary" because its the only one that allows to cast through *private inheritance*... not that it is common in my world but worth mentioning. – ereOn Jan 30 '15 at 19:23
  • "The behaviour of the C-style cast is to apply the least powerful cast that is required to allow compilation to succeed." Not quite. A C-style cast to an ambiguous base class is interpreted as a `static_cast`, even though it is ill-formed, rather than a `reinterpret_cast`, which would be well-formed. – T.C. Jan 30 '15 at 19:24
  • 2
    Wouldn't a `const_cast` do the same thing in this case? Blaming the C-style cast is a bit misleading. – Mark Ransom Jan 30 '15 at 19:49