This Time Self-Hosted
dark mode light mode Search

In APIs you should always accept the stricter pointer

Yet another entry on some insights of C/C++ low level code, this time, rather than a performance issue, it’s a correctness issue, related to one of the warnings added by default by GCC 4.2: deprecated conversion from string constant to ‘char*‘. It will also be a shorter entry as I don’t have to dig into ASM code generated.

The content of this entry formed in my mind when I seen a lot of those warnings on the newest version of QSynth (which I’m committing to the tree right now). I first thought there was a pointer simply declared as char* rather than const char*, and then assigned a literal (“this is a literal” if you didn’t know the term).

Unfortunately the problem is not this simple; the warnings appear when using literals to call the fluidsynth API (of which QSynth is a frontend). And this because fluidsynth API declares all the string parameters as char*.

As the title of the entry suggest, this is not really good. You should always accept the stricter pointer you can, this means that if you need strings, you should accept a pointer to constant characters (const char*), unless you need to actually modify the string. In almost all standard cases you don’t need to modify the string.

This makes it possible for the compiler to stop you from changing the data in the string (which also stops you from using = rather than == if you’re going to do a comparison), and removes the cause of the warnings above.

As you seen in yesterday’s post, the const specifier in front of char makes it a pointer to constant characters, so the pointer can be changed, but the pointed characters can’t. This means that you’re not passing a constant parameter (like in the case of a const int parameter), you’re passing a variable pointer to a constant string.

The const specifier does not in any way require that the object resides on .rodata section, so that the content is certainly constant, as it’s more an indication to the compiler. On the other hand, not specifying const requires, even if GCC does not enforce this, that the object does not reside on .rodata section. You can probably read in this difference the main point of this entry:

You can pass a pointer to non-constant objects to a function expecting a pointer to constant objects, you shouldn’t pass a pointer to constant objects to a function expecting a pointer to non-constant objects.

Note that I used the form “shouldn’t” because there are libraries which functions take non-constant object pointers, even if they don’t change the content at all (and thus should accept constant object pointers). This seems to be the case for fluidsynth.

For this reason, if your API accepts a pointer to an object, and you don’t modify the object in any way, you should always use const in the parameter declaration. There are more implications when passing pointers to constant structures that have pointers to other structures, but that’s a topic for another day.

Now, to return on my original problem: do I fix fluidsynth to accept constant strings, and send the patch upstream? Or leave that to upstream to deal with?

Comments 3
  1. const char * is still assignable… It doesn’t prevent most = vs == screwups. You want const char * const to catch those.

  2. I was referring to loops like this:

    while(*p) {  if ( *p == 'a' ) {    dostuff();  }  p++;}

    I should have been clearer.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.