-1

First off let me state that I understand the difference between:

const char *a;

and

char * const a;

and

const char * const a;

However lately I am repeatedly encountering the latter when being used to pass parameters to a function, to give an example the Maxmind GeoLite2 mmdb C API for reading the database files uses the following format for every pointer parameter:

const T * const 

Example: https://github.com/maxmind/libmaxminddb/blob/master/include/maxminddb.h#L203

extern int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb);

I have a solid understanding of C/C++ and the x86 or x86-64 that C/C++ is often compiled into and I understand that the pointer to the filename and the pointer to the MMDB_s are both stack-allocated copies (or passed by register in the case of x86-64) so what purpose is there to make the pointer const?

Am I missing something here or are they unnecessarily flooding their API with const pointers which really have no end effect on the person using them?

user6567423
  • 353
  • 4
  • 9
  • 1
    Why don't you [read up on const](https://en.wikipedia.org/wiki/Const_(computer_programming)) – machine_1 Mar 19 '18 at 18:43
  • 2
    The same reason why you might use `const int i = ...;` - to tell the compiler (and the reader) that you won't modify it. – Kevin Mar 19 '18 at 18:43
  • I understand using const to declare a variable because there is definitely potential benefits from the compiler, but as explained here https://stackoverflow.com/questions/27466642/what-kind-of-optimization-does-const-offer-in-c-c-if-any there isn't any benefits to having a const parameter which has to be copied anyway. I guess it just seems like a superfluous convention that doesn't serve any real purpose other than preventing other programmers or readers from thinking it gets modified when it doesn't even matter if it does. – user6567423 Mar 19 '18 at 18:52
  • 1
    The person implementing `MMDB_open` wants to guard against themselves doing `filename = ...` inside `MMDB_open`. – nos Mar 19 '18 at 18:55
  • Seems superfluous, thanks though. – user6567423 Mar 19 '18 at 18:57
  • 2
    But it's not superfluous to the person writing MMDB_open - it might help them catch real bugs in their code. – nos Mar 19 '18 at 18:57

1 Answers1

2

The C standard specifically says that top-level const qualifiers are ignored in function prototype declarations. (N1570 §6.7.6.3p15, the sentence in parentheses at the very end of the paragraph.) What that means is, from the perspective of code trying to call MMDB_open, the declarations

extern int MMDB_open(const char *const filename, uint32_t flags,
                     MMDB_s *const mmdb);

and

extern int MMDB_open(const char *filename, uint32_t flags,
                     MMDB_s *mmdb);

are semantically the same. So you are correct to think that these qualifiers are unnecessary.

However, they are not pointless, because, from the perspective of the implementation of the function, they are not the same. Inside the code for MMDB, they have this function definition somewhere

int
MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb)
{
    // code here
}

and the code in the body of this function is not allowed to modify the filename and mmdb variables (but it is allowed to write through mmdb and modify what it points to). That's why they put the qualifiers on those variables in the first place.

And they probably copied the qualifiers into the prototypes in the public header files because they wanted the prototypes to match up to the function definitions exactly. That makes maintaining the header file easier.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • I guess my question is why bother doing this? The only reason that seems valid is to help the reader see that the member won't be modified, but how often is that actually going to be useful information? When I edit somebody elses code I'm rarely ever worried that their pointer-parameters are getting modified... especially stuff like 'filename'. – user6567423 Mar 19 '18 at 18:53
  • 1
    @user6567423 Reread the part of my answer that begins "However, they are not pointless", please. – zwol Mar 19 '18 at 18:54
  • I understand locally you cannot modify the pointer inside the function, what purpose does that serve? It's superfluous information to the reader/programmer that just takes up space. – user6567423 Mar 19 '18 at 18:56
  • 2
    @user6567423 It's superfluous to _you_ but it's not superfluous to the maintainers of the library, and it's in the public headers because it's easier to maintain the public headers when the prototypes match the definitions exactly. – zwol Mar 19 '18 at 18:59
  • 2
    If you don't understand how being forbidden to do `filename = ...` in the body of `MMDB_open` might catch bugs, please ask a new question about that. – zwol Mar 19 '18 at 19:00