[g++] warning: deprecated conversion from string constant to ‘char*’


Just stumbled on to this problem/fix while writing some C++ code for my CS courses…

warning: deprecated conversion from string constant to ‘char*’

I hadn’t really thought about this much, as previous versions of g++ (such as the 3.4.3 version we’re using on our university systems) never complained about this issue, but g++ 4.2.3 does. The fix, as I found from multiple posts around the web, is to change all function arguments that will be expected to take a string constant from “char *” to “const char *”. For example:

Function Call:

class.someFunction("");

Original Function Prototype:

void class::someFunction(char *);

Updated Function Prototype:

void class::someFunction(const char *);

I’m somewhat new to C++ (OSU taught Java and I code in C# for the day job), so please give me a bit of slack on this one if you’re a seasoned pro. 😉

As always, comments and questions are welcome via my comment box. Thanks for reading!

36 Comments

  1. Dave Higginbotham says:

    I’ve run into the same thing and it’s giving me hearburn. I’ve always believed that there’s no such thing as deprecation in C++. To me “deprecation” is abandonment of backwards compatibility. I’ve been trying to find out if the standards committee actually approves of deprecation or whether these error messages are simply misleading.

  2. E. Otoo says:

    Call the function by casting the parameter to
    “char *” type. Instead of function call
    class.someFunction(“”);
    use
    class.someFunction((char *)””);

    That should fix your warning problem

  3. Andrew Davie says:

    Surely E.Otoo’s advice is incorrect. The compiler will still complain. foo(“”) is exactly the same as foo((char *)””) to the compiler, and you’ll get the same warning. The issue is that the compiler is warning you that the function is allowed to modify the contents of the char * memory (as it’s not const), but since you have passed in a string literal (via pointer, but still a literal) then in theory the function could stomp over this, and all following memory. It’s not safe, and it’s the very reason there’s a warning.
    The correct thing to do is to define the parameter in the function as a const char *. That is, void foo(const char *p) instead of void foo(char *p).

  4. Marco says:

    It’s not about deprecating existing features. Rather gcc tries to enforce more of the C++ rules that previously were ignored. If you have a string constant- well, obviously it’s going to be a CONST and not a modifiable string pointer, thus it should not be declared as non-const.

    With a declaration like void class::someFunction(char *) you are essentially saying to the user: give me a pointer to a string and I’ll change it somehow.
    void class::someFunction(const char *) on the other hand says: I only want to read your string and won’t try to do anything to it.

  5. An example where there is not real solution to this problem:
    #include
    #include “image.xpm”
    Pixmap p, mask;
    XpmCreatePixmapFromData(display, window, image_xpm, &p, &mask, NULL);

    I *could* change the data in the xpm to be a const, but it was produced by gimp. I *cannot* change XpmCreatePixmapFromData, as it will choke on a const.

  6. bwmaister says:

    My issue with this (since we’re on the internet) is that I get a warning about this:

    char* world = “hello”;

    really gnu? Don’t you think that I know that I can modify a string that I’m declaring non-const?

    Unless there’s a good reason for me to *not* do that, that you can think of?

  7. mark hahn says:

    -Wno-write-strings is what you want.

  8. Marach says:

    mark hahn THANK YOU!!! That one gcc option removes hundreds of annoying warnings! BTW, I don’t care about warnings since I port a C game to C++ and I DON’T NEED A COMPILER AGREEMENT to know the app works! That deprecation is one of the biggest humanity mistakes 🙂 .

  9. miguel says:

    Cast away the constantness!
    In each new release of gcc I’ve needed to add more casts to my old code.
    It’s a good thing. For it removes the compiler the guess work and shows you potential bugs sooner.

  10. Doug says:

    Gaah! Wrong answers people!

    1) Avoid casts just to clear up warnings — it’s probably masking a problem to begin with. It might not bite you now, but you never know.

    2)

    char* world = “hello”;

    … is still incorrect and for good reason. You’re defining a modifyable pointer to a constant. If you want a non-const version, try:

    char world[] = “hello”;

    3) On those rare occasions (see Scott’s comment above) that you’re dealing with a const string that has to go to something that can’t be modified, there are two approaches:

    a) const_cast(str) — works, but you should make sure that the result is not modified.

    b) strncpy() the const string to a non-const string — if you can take the performance hit (most likely you can), this is the “safest” option. Just make sure you deal with allocations, etc. properly.

    See this in light of class const-ness in C++ … what if the string literal were a const std::string& instead, and the function wanted a std::string&? Of course you’d want the compiler to complain (it’s actually an error in this case). What do you do about it? You can either change the function to be const std::string& or make a local copy of the variable to pass in. As a last resort, const_cast can be used.

    To further enlighten:

    void func(std::string&);

    …cannot be called with a string literal, but

    void func(const std::string&);
    void func(std::string);

    …both can. The non-reference version creates a local copy, as I suggested above.

    — Doug

    1. Josh Perry says:

      Beautiful and accurate explanation! Thanks Doug.

    2. andigor says:

      Hello

      I have such initialization
      char * arr[] = {”aaaa”, “bbbb”};
      My question is how can I rewrite this without getting warning about “deprecated converion”

      1. fileoffset says:

        cosnt char* arr[] = {”aaaa”, “bbbb”};

      2. vikram singh says:

        char arr[][5] = {“aaaa”, “bbbb”};

    3. vonrey says:

      THANKS DOUG!
      Really, from my deepst heart; I ‘ve to compile with a lot of horrible options my code and I realized that making the task of reading files containing NULL (any binary files) is annoying in C; so when I caste to C++98 it treated the warnings and errors, and I was really desperate.
      Once more, thanks =) be happy!

  11. Thanks! This helped me a bunch today.

  12. Pete says:

    oooh its fixed ^_^ Thank you very much.
    I can’t help but wonder if there is another way to fix it like others have said in the comments, is this actually fixing it?

  13. anon says:

    “It’s not about deprecating existing features. Rather gcc tries to enforce more of the C++ rules that previously were ignored.”

    Indeed: the relevant portion of the ISO C++ Standard (2.13.4.1) :

    “An ordinary string literal has type “array of n const char” and static storage duration (3.7), where n is the size of the string as defined below …” etc.

  14. Eduardo says:

    The suggestion in this post worked great for me. Many thanks for sharing.

  15. Carl says:

    Oh, but wait… there’s another question…

    I’m trying to learn C++, and this is giving me quite a headache. (For those who want to follow along at home, I’m doing a programming exercise out of C++ Primer Plus by Stephen Prata, Fourth Edition, chapter eight, exercise 5).

    The exercise is in template functions, and making specialized functions. I’ve got the following prototypes:

    template T maxn(T x[], int n);
    template char * maxn(char * x[], int n);

    I’m calling the specialized function in the following way:

    char * stringArray[] = { “My”, “mangy”, “dog”, “has”, “fleas” };

    char * maxString = maxn(stringArray, 5);

    Which causes the warning described in this thread, 5 times. So I could change it to this:

    const char * stringArray[] = { “My”, “mangy”, “dog”, “has”, “fleas” };

    But then the generic function is called rather than the specialized one. (char * [] != const char * []) Ok, so I change my function prototype to this:

    template char * maxn(const char * x[], int n);

    But, then I get:

    error: template-id maxn for char* maxn(const char**, int) does not match any template declaration

    Oh, wait… I figured it out… the prototype should be:

    template const char * maxn(const char * x[], int n);

    I’m going to go ahead and post my question and solution for anyone else who may be trying to understand this.

    Quite the interesting exercise. (Thoroughly enjoying this book, though.) I’m a C# developer as well, and I believe that C++ is not getting the recognition it deserves due to Microsoft’s attempt at java-cloning (a.k.a. C#) and poor naming choice. C# is NOT the new C++ people. Keep teaching C++ in colleges and universities! The whole world doesn’t run on top of a managed runtime in the Winders environment! 🙂

    1. carpetkiss says:

      Thanks for this post – I was compiling some legacy code & got 1000’s of warnings. I had a brainfart & was tempted to cast the string literals as char* at first, but changing the function calls to const char* is obviously correct.
      However,using the std::string type would be best surely.
      Windows C++ is going the same way, believe it or not, & making their C++ more ANSI-compliant – there was a big jump with VS2005(as I discovered to my cost when porting a 50 project VS6.0 COM/ATL solution to VS2005).
      You are so right Carl, about C++. Teaching it means teaching about so many fundamental ideas. Half the worlds code is C++
      (and the other half is COBOL 🙂
      I have been working through Bjarne Stroustrups C++ book – he is The Man.

  16. andigor says:

    Hello

    I have such initialization
    char * arr[] = {“aaaa”, “bbbb”};
    My question is how can I rewrite this without getting warning about “deprecated converion”

  17. Carl says:

    This can be either:

    const char * arr[] = { “aaaa”, “bbbb” }

    or

    char const * arr[] = { “aaaa”, “bbbb” }

    This means that the values in the array are constant.

    (I believe the first is more correct, but I’m not an expert… maybe they’re equally correct. My compiler handles both.)

    This would *not* be correct:

    char * const arr[] = { “aaaa”, “bbbb” }

    Which means that the pointers to the values in the array are constant but the values are not necessarily constant.

  18. andigor says:

    Thanks for your answer… But I need exactly non-constant version. I think it must be something like

    char * arr[][] = {“aaaa”, “bbbb”};

    But this variant does not work.

  19. Carl says:

    Well, here’s the way to get rid of the warning… but doing this makes it possible for your program to encounter a runtime error something in your program tries to modify anything in the memory location of arr[0] or arr[1].

    It is *highly* recommended that you don’t do this, instead use the suggestion I had above. After all, this tells the compiler that “aaaa” and “bbbb” are not constant… when in fact, they are.

    char * arr [] = { (char*)”aaaa”, (char*)”bbbb” };

    int main()
    {
    arr[0] = (char*)”cccc”;
    }

  20. Carl says:

    Looking at your most recent post again, though… you may be asking about this… the following are all equivilent:

    const char ** arr { “aaaa”, “bbbb” }
    const char * arr [] { “aaaa”, “bbbb” }
    const char arr[][] { “aaaa”, “bbbb” }

    For every * you add or remove, you must conversely add or remove a [].

  21. Brad says:

    Thanks for the tip! While it’s kinda silly that you have to do this, it’s nice to know how to make the compiler shut up.

    Protip:
    I didn’t want to break generality by declaring the argument always a constant, so I overloaded the function like this:

    void foo (char* s){
    //code
    }

    void foo (const char* s){
    // same code
    }

    I wish I didn’t have to duplicate the code twice though. Anyone have any suggestions?

    1. AP says:

      maybe…

      template
      void foo ( T s ) {
      // code
      }

      1. AP says:

        i mean

        template
        void foo ( T s ) {
        // code
        }

        1. AP says:

          it shoul be

          template 
          void foo ( T s ) {
          // code
          }
          
          1. AP says:

            another try to set the brackets…

            template &lt typename T &gt
            void foo ( T s ) {
            // code
            }
            
  22. anisha kaul says:

    mark hahn
    -Wno-write-strings is what you want.

    Thanks for useful info, but i wanted to know how does these warnings get suppressed by this option ?

  23. rb says:

    Thanks a lot for this tip. It works fine. Though I seriously don’t know why they changed it. :-/

  24. padme says:

    thanks for this great info, saved my life:D

  25. JohnColburn says:

    Just to tag my two cents, since google puts this high on the list:

    The error is because you are passing a CONSTANT CHARACTER ARRAY into a NON-CONSTANT POINTER.

    This is a problem because: Your function might try to modify a NON-CONSTANT POINTER which points to a CONSTANT CHARACTER ARRAY, which would be a serious error.

    The correct solution: Declare the variable constant in the function definition —OR— use a non-constant string with the function.

    If your function does not modify the string, you should declare the arg as “const char *foo”. Note that it’s 100% okay to pass a non-const pointer into a const argument; the pointer will be automatically treated as constant inside the function which is fine because you are not modifying it.

    If your function DOES modify the string, you should absolutely NOT pass in a string literal in any case. There is no circumstance where you should attempt modify a constant string in-place; that’s the definition of the ‘const’ modifier.

    If you want to modify a string that comes from a const source (such as a literal or some strange behavior in an external library), you’ll just need to copy the value into a non-const buffer and modify it there. When you think about what ‘const’ means it becomes obvious why you want the compiler to enforce this.

    1. willwm says:

      Thank you for the clarification! =)

Leave a Comment