Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

struct keyword in function parameter, and const-correctness

I have an opaque type in my library defined as:

typedef struct MyOpaqueType* MyType;  // easier to type for client code

I can't pass a pointer-to-const struct around using the typedef, so some functions look like:

void UsePointerToConst ( const struct MyOpaqueType * )

instead of:

void UserPointerToConst( const MyType ) // can't use, is really constant pointer

So, given this, I have two questions: Is the struct keyword in the parameter list only necessary in C? Is there a better way to do this? Should I create a typedef such as:

typedef const struct MyOpaqueType* ConstantMyType; ?
like image 650
Cat Zimmermann Avatar asked Dec 28 '22 18:12

Cat Zimmermann


2 Answers

Is the struct keyword in the parameter list only necessary in C?

Yes. See Jens Gustedt's answer.

Is there a better way to do this?

Just typedef the struct, not the pointer. This is better because

  • you only need one typedef instead of one for each of {MyOpaqueType, MyOpaqueType *, MyOpaqueType const *, MyOpaqueType *const and MyOpaqueType const *const} and all variants involving restrict (which doesn't exist in C++),
  • it's clear to the user that pointer semantics apply, i.e., passing the datatype around is really a matter of pointer copying (no performance worries), users are less likely to forget cleaning up after use, C++ users may use smart pointers, and
  • it's a common C convention (think FILE *).

There's also no danger; when someone forgets the *, they get a compiler error.

like image 141
Fred Foo Avatar answered Jan 19 '23 00:01

Fred Foo


In C++ a typedef of the same name as a struct is assumed as long as there is no other identifier with that name. So something like a function stat that receives a struct stat* as an argument:

int stat(const char *path, struct stat *buf);

is even allowed in C++. (This is a real world example.)

So you are always better of with forward declarations like

typedef struct toto toto;

which reserves the token toto in the identifier and in the struct name space. Then you can have your function interface declared for C and C++. But don't forget the extern "C" if you want to access it from C, too.

See also: this answer on SO and struct tags are not identifiers in C++.

like image 34
Jens Gustedt Avatar answered Jan 18 '23 22:01

Jens Gustedt