Typedef and const

K

kid joe

Hi all,

Ive got an opaque type encapsulated with a typedef, say

typedef struct my_obj *my_obj_handle;

Now what I want is to define a function type that takes one of these
handles in such a way that the function cant modify whats pointed to in
accordance with Data Hiding principals.

If I do something like

my_function(const my_obj_handle H)
{
*H = something;
}

then this will compile OK because the const applies to H not *H!

Also if I swap the const to the right and have my_function(my_obj_handle
const H) then its still H thats constant and not *H!

How can I define a function like
my_function(const struct my_obj *H)
but using the typedef instead of struct my_obj?

Cheers,
Joe
 
L

luserXtrog

Hi all,

Ive got an opaque type encapsulated with a typedef, say

typedef struct my_obj *my_obj_handle;

Now what I want is to define a function type that takes one of these
handles in such a way that the function cant modify whats pointed to in
accordance with Data Hiding principals.

If I do something like

my_function(const my_obj_handle H)
{
  *H = something;

}

then this will compile OK because the const applies to H not *H!

Also if I swap the const to the right and have my_function(my_obj_handle
const H) then its still H thats constant and not *H!

How can I define a function like
my_function(const struct my_obj *H)
but using the typedef instead of struct my_obj?

I don't understand why this would be necessary.
Of what use would such a function be if it could be defined?
 
K

Keith Thompson

kid joe said:
Ive got an opaque type encapsulated with a typedef, say

typedef struct my_obj *my_obj_handle;

Now what I want is to define a function type that takes one of these
handles in such a way that the function cant modify whats pointed to in
accordance with Data Hiding principals.

If I do something like

my_function(const my_obj_handle H)
{
*H = something;
}

then this will compile OK because the const applies to H not *H!

Also if I swap the const to the right and have my_function(my_obj_handle
const H) then its still H thats constant and not *H!

How can I define a function like
my_function(const struct my_obj *H)
but using the typedef instead of struct my_obj?

Following the usage of FILE in <stdio.h>, declare your typedef as an
alias for the struct, not for a pointer to the struct, and make your
functions take pointer arguments.

Here's a simple example. Note that struct hidden is an incomplete
type except within foo.c.

===== foo.h =====
typedef struct hidden handle;

handle *create(int x);
int get(const handle *arg);
void destroy(handle *arg);

===== foo.c =====
#include <stdlib.h>
#include "foo.h"

struct hidden {
int x;
};

handle *create(int x) {
handle *result = malloc(sizeof *result);
if (result != NULL) {
result->x = x;
}
return result;
}

int get(const handle *arg) {
return arg->x;
}

void destroy(handle *arg) {
free(arg);
}
 
T

Tim Rentsch

Keith Thompson said:
kid joe said:
Ive got an opaque type encapsulated with a typedef, say

typedef struct my_obj *my_obj_handle;

Now what I want is to define a function type that takes one of these
handles in such a way that the function cant modify whats pointed to in
accordance with Data Hiding principals.

If I do something like

my_function(const my_obj_handle H)
{
*H = something;
}

then this will compile OK because the const applies to H not *H!

Also if I swap the const to the right and have my_function(my_obj_handle
const H) then its still H thats constant and not *H!

How can I define a function like
my_function(const struct my_obj *H)
but using the typedef instead of struct my_obj?

Following the usage of FILE in <stdio.h>, declare your typedef as an
alias for the struct, not for a pointer to the struct, and make your
functions take pointer arguments. [snip example code]

There's an important difference here between the "handle"
parameters and FILE's. A FILE is guaranteed to be an object
type. The type (struct my_obj) is going to be (in client code)
an incomplete type. Given that (struct my_obj) is an incomplete
type, it seems better to incorporate the pointerness into the
defined type name.

If the distinction between a handle and a "read only" handle (in
the sense of a (const struct my_object *) type) is important to
client code -- and most likely it will not be -- then it's easy
enough to add a typedef for the additional name:

typedef struct my_object *handle;
typedef struct my_object const *handle_readonly;

More likely, the "read only" handle types will be important only
to the module that defines the type (and where (struct my_obj) is
a complete type). In those cases, the read-only-ness can be put
completely inside the implementing module and the functions that
need it:

/* the file that implements struct my_obj */

typedef const struct my_obj sacred_my_obj;

void
blah( handle foo_writable ){
sacred_my_obj *foo = foo_writable;
/* ... now use 'foo' ... */
}

Notice that, if client code never has to save a "read only"
handle, then there is no reason to use a "read only" handle type
in any public interface, since regular handles will always
satisfy a "read only" handle type passed through an function
interface. There's no reason to make the "read-only-ness"
part of the interface specification, since as far as client
code goes it can't tell the difference.
 
T

Tim Rentsch

Tim Rentsch wrote:
[...]
If the distinction between a handle and a "read only" handle (in
the sense of a (const struct my_object *) type) is important to
client code -- and most likely it will not be -- then it's easy
enough to add a typedef for the additional name:

typedef struct my_object *handle;
typedef struct my_object const *handle_readonly; [...]
Notice that, if client code never has to save a "read only"
handle, then there is no reason to use a "read only" handle type
in any public interface, since regular handles will always
satisfy a "read only" handle type passed through an function
interface. There's no reason to make the "read-only-ness"
part of the interface specification, since as far as client
code goes it can't tell the difference.

A read-only handle type that is a pointer to const is useful for
expressing logically const operations. It allows the client to write his
own functions that don't modify said object, and for it to work with the
type system (non-const implicitly converts to const, but not the other way
around). [snip]

I agree that it /can/ be useful. But usually it isn't because
read-only-ness isn't especially meaningful to client code (for
opaque handles). It can be done, but in most cases the gain
is so little it isn't worth the cost.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top