larienna
larienna

Reputation: 151

Why "const int" to "int" conversion works but "const char[]" to "char *" does not

That is something that always intrigued me with the C++ language. With the appearance of the "const" identifier, it was supposed to replace the use of #define statement to declare constants. But as I stated to use them, I ended up in a const char to char conversion error madness.

Recently, I stated doing in class constants like done in Java. So I decided to declare something like this.

private: const static int NB_FIELD = 22;

This works perfectly. A function returning a int can return a "const int" without any problems.

But now if I try to do the same with a string like this:

private: static const char ERRORSTR [ 6 ];

Which constains the string "Error", it will generate const char to char conversion problems like in this function.

char* EnhancedSQLobject::get_SQLname ( int index )
{
   if ( index < p_nb_field && index >= 0 )
      return ( p_SQLfield_ptr [ index ] . SQLname)

   return ( ERRORSTR );

}

Now some people will say change the return value for const char* but I can't because if the index is valid, it will return a non-const variable, but if the index is invalid, it will return a constant error string.

So my choice are either to make the error string non-constant, or create a constant using #define statements. I remember a long time ago trying to define everything as a const char, but eventually it blew up somewhere else in the chains of conversion. Making it just easier to use regular char (the String class is not a option for me)

This is plain ridiculous, why implement a feature that only works for only a part of the variable types. I imagine it's related to the fact that stings are in fact table of characters so it probably return a pointer instead of a value.

Upvotes: 1

Views: 1408

Answers (3)

b4hand
b4hand

Reputation: 9770

Just so you know, using a #define will not work as you expect it will, at least not if you're truly using C++ and not C.

In C++, a string literal is const, thus if you declare:

#define ERRORSTR "ERROR"

And you try to return ERRORSTR from get_SQLname, it may cause undefined behavior if you try to modify the returned string. It's quite likely that your compiler is only issuing a warning for this because this fact that string literals are const was not always true in C++ a long time ago.

#include <iostream>

#define BLAH "blah"

char *foo() {
    return BLAH;
}

int main(int argc, char *argv[]) {
    std::cout << foo() << std::endl;
}

On my compiler, I see the following warning:

so.cpp:6:12: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]

The reality is that using #define for constants, especially string constants is unsafe for exactly this reason, and thus should be avoided. const provides you with some level of safety by the compiler, and if the compiler is telling you that the conversion is unsafe, there is a reason for that error, and you should try to figure out what that reason is and solve the problem instead of just trying to silence the error or find some other workaround. In fact, relying on behavior from C is generally a code smell in C++ and relying on the semantics of another language like Java is even worse. Despite their similarities in syntax, Java, C, and C++ are all very different from each other in their actual semantics. It would be best for you to learn those differences instead of just trying to apply the knowledge you know from one language to another.

Upvotes: 0

Joseph Mansfield
Joseph Mansfield

Reputation: 110658

In one case you are talking about casting const int to int, while in the other you are casting const char* to char*. These really are different situations that should behave differently, because the latter has a level of indirection added (the pointer). You absolutely can cast a const char to a char, but that's not what you're doing.

Consider the following erroneous code:

const int i = 50;
int j = i;
int* p = &i; // ERROR

I attempt to do int j = i; and that is fine. The original i object remains const and the j object is given the same value as i. However, if I attempt to do int* p = &i;, we have a problem. If this would compile, we would have p pointing at a const int, even though it tells us its pointing at a non-const int. This would allow us to modify the const object i through the pointer p - that's very bad.

You have the same situation here, just with chars. All of the chars in your ERRORSTR are const. You can't then return a char* that points at any of those chars, because that would be lying. The pointer isn't pointing at a non-const char, but at a const char.

ints and chars don't behave any differently in this respect.

However, I think you've only entered this predicament because of poor interface design. Why does your function return a special string when it can't find the "SQLname" (whatever that is)? What if, for example, the string "Error" was actually a valid name? How would the caller of the function tell the difference? I'd argue that if your function isn't able to fulfill the action of get_SQLname (that is, it isn't able to get the name), it should throw an exception.

On top of this, you should be using std::string instead of C-style char*s.

Upvotes: 2

Barry
Barry

Reputation: 302827

There's a difference between the two conversions. For int:

const int ci = 7;
int i = ci; // fine...
++i;        // ... because ci is still 7

But if you could do it for char*:

const char msg[] = "Hi";
char* p = msg; // not OK...
*p = 'B';      // ... because now msg = "Bi" 
               //     and it was supposed to be const!

The actual equivalent to the former for pointers would be:

char * const cc = someBuf();
char * c = cc; // this is totally OK
++c;           // ... because we're not modifying cc in any way

It's the difference between a const pointer and a pointer to const.

Upvotes: 0

Related Questions