468,554 Members | 1,891 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,554 developers. It's quick & easy.

Opaque pointers

Can anyone explain what's an opaque pointer and how it's implemented in
C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
..
..
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?

Any answers is much appreciated.

Aug 17 '06 #1
18 10720
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?

Any answers is much appreciated.
In your header file, you'd have something along the lines of:

foo.h
-----
typedef struct foo foo;

foo *create_foo(void);
void destroy_foo(foo *ptr);

void use_foo(foo *ptr);

The actual definition of 'struct foo' goes in the source file:

foo.c
-----
struct foo
{
/* ... */
};

So that it's only foo.c that knows what the contents of a struct foo
are. The contents are hidden, ie opaque, from everything that merely
includes foo.h - all you can do is pass pointers around.

--
rh

Aug 17 '06 #2
Richard Harnden wrote:
>
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?

Any answers is much appreciated.

In your header file, you'd have something along the lines of:

foo.h
-----
typedef struct foo foo;

foo *create_foo(void);
void destroy_foo(foo *ptr);

void use_foo(foo *ptr);

The actual definition of 'struct foo' goes in the source file:

foo.c
-----
struct foo
{
/* ... */
};

So that it's only foo.c that knows what the contents of a struct foo
are. The contents are hidden, ie opaque, from everything that merely
includes foo.h - all you can do is pass pointers around.
That's wrong.
The defintion of the stuct type needs to be in the header file.
Otherwise,
void destroy_foo(foo *ptr);
wouldn't mean anything in the header file.

--
pete
Aug 17 '06 #3
pete wrote:
>
Richard Harnden wrote:

chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?
>
I read about this concept in the book "C interfaces and
implementations".
>
Here's an example from the book (list.h - available from the website):
>
#define T List_T
>
typedef struct T *T;
struct T {
T rest;
void *first;
};
>
extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...
>
It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).
>
But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?
>
Any answers is much appreciated.
>
In your header file, you'd have something along the lines of:

foo.h
-----
typedef struct foo foo;

foo *create_foo(void);
void destroy_foo(foo *ptr);

void use_foo(foo *ptr);

The actual definition of 'struct foo' goes in the source file:

foo.c
-----
struct foo
{
/* ... */
};

So that it's only foo.c that knows what the contents of a struct foo
are. The contents are hidden, ie opaque, from everything that merely
includes foo.h - all you can do is pass pointers around.

That's wrong.
The defintion of the stuct type needs to be in the header file.
Otherwise,
void destroy_foo(foo *ptr);
wouldn't mean anything in the header file.
In general, it's only object defintions and function definitions
that don't belong in header files.
Typedefs and enums are two kinds of definitions
that are typically OK in header files.

I'm not too familiar with inline functions.
I think they can go in header files too,
but I'm not sure.

--
pete
Aug 17 '06 #4
pete wrote:
Richard Harnden wrote:
>chankl wrote:
>>Can anyone explain what's an opaque pointer and how it's implemented in
C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?

Any answers is much appreciated.
In your header file, you'd have something along the lines of:

foo.h
-----
typedef struct foo foo;

foo *create_foo(void);
void destroy_foo(foo *ptr);

void use_foo(foo *ptr);

The actual definition of 'struct foo' goes in the source file:

foo.c
-----
struct foo
{
/* ... */
};

So that it's only foo.c that knows what the contents of a struct foo
are. The contents are hidden, ie opaque, from everything that merely
includes foo.h - all you can do is pass pointers around.

That's wrong.
The defintion of the stuct type needs to be in the header file.
Otherwise,
void destroy_foo(foo *ptr);
wouldn't mean anything in the header file.
Only a forward declaration is needed, so the 'content'
of the struct becomes opaque to users of the implementation
of foo.h

With the above foo.h, I can include it and do
foo *h = create_foo();
use_foo(h);
destroy_foo(h);
Aug 17 '06 #5
"chankl" <ch*******@yahoo.com.sgwrites:
Can anyone explain what's an opaque pointer and how it's implemented in
C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...
Ugh. Is that really the code from the book?

I can't think of any good reason for the macro defining T as List_T.
It just obfuscates the code.

Furthermore, it uses the same identifier, T (um, I mean List_T) as the
tag for the struct and as a typedef for a *pointer* to the same
struct. So "struct T" is a structure, and "T" is a pointer to that
same structure.
It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?
Yes, any code that includes that header can access the members of the
structure.

If you really want to declare an abstract pointer type, you can make
it point to an *incomplete* structure type:

typedef struct hidden *abstract_pointer;

and hide the actual definition of "struct hidden" inside a source file
that implements the library.

You can do this if you want to make it impossible for client code to
see the innards of your structure. An alternative is to put the
structure definition in the visible header, and just tell clients not
to use it. A good example of this is the type FILE in <stdio.h>; the
documented interface just uses FILE* as an abstract pointer type, but
client code *could* access the members of the type FILE. In practice,
this isn't a problem.

Here's a small example of a library declaring an abstract pointer type
and hiding the pointed-to type inside the implementation. There are
three source files, lib.h, lib.c, and main.c.

Note that this declares a typedef for a pointer type, which is
*usually* a bad idea. In this case, the client code doesn't make use
of the fact that it's a pointer. An alternative would be to declare a
typedef for the hidden struct type, and have the code use an explicit
pointer type. (It wouldn't be able to declare an object of the
structure type, since it's incomplete.)

=============== lib.h ===============
#ifndef LIB_H
#define LIB_H

typedef struct ap_hidden *abstract_pointer;

abstract_pointer ap_create (char *s);
char *ap_get (abstract_pointer x);
void ap_destroy (abstract_pointer x);

#endif
========================================

=============== lib.c ===============
#include "lib.h"
#include <string.h>
#include <stdlib.h>

struct ap_hidden {
char *str;
};

abstract_pointer ap_create(char *s)
{
struct ap_hidden *const p = malloc(sizeof *p);
const size_t size = strlen(s) + 1;
if (p == NULL) {
return p;
}
p->str = malloc(size);
if (p->str == NULL) {
free(p);
return NULL;
}
strcpy(p->str, s);
return p;
}

char *ap_get(abstract_pointer x)
{
return x->str;
}

void ap_destroy(abstract_pointer x)
{
if (x == NULL) {
return;
}
free(x->str);
free(x);
}
========================================

=============== main.c ===============
#include "lib.h"
#include <stdio.h>

int main(void)
{
abstract_pointer x = ap_create("Hello, world");
if (x == NULL) {
printf("ap_create() failed\n");
}
else {
printf("ap_create() ok, ap_get(x) --\"%s\"\n", ap_get(x));
}
ap_destroy(x);
return 0;
}
========================================

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Aug 17 '06 #6
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented
in C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I
missing the meaning of opaque?

Any answers is much appreciated.
I seem to remember that Chris Torek had plenty to say on this relatively
recently [and see his 'previously' too]. So, I'd advise you to search the
whole of c.l.c for Chris' stuff [always valuable] - Google's you best mate
here.

--
==============
*Not a pedant*
==============
Aug 17 '06 #7
"Nils O. Selåsdal" wrote:
>
pete wrote:
Richard Harnden wrote:
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?

Any answers is much appreciated.

In your header file, you'd have something along the lines of:

foo.h
-----
typedef struct foo foo;

foo *create_foo(void);
void destroy_foo(foo *ptr);

void use_foo(foo *ptr);

The actual definition of 'struct foo' goes in the source file:

foo.c
-----
struct foo
{
/* ... */
};

So that it's only foo.c
that knows what the contents of a struct foo
are. The contents are hidden, ie opaque,
from everything that merely
includes foo.h - all you can do is pass pointers around.
That's wrong.
The defintion of the stuct type needs to be in the header file.
Otherwise,
void destroy_foo(foo *ptr);
wouldn't mean anything in the header file.
Only a forward declaration is needed, so the 'content'
of the struct becomes opaque to users of the implementation
of foo.h

With the above foo.h, I can include it and do
foo *h = create_foo();
use_foo(h);
destroy_foo(h);
Thank you.
I hadn't noticed the typedef line:

typedef struct foo foo;

--
pete
Aug 18 '06 #8

chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I missing
the meaning of opaque?

Any answers is much appreciated.
There are actually several different questions in here.

One question is about how C works. If you can #include
the header file, then yes you can indeed dereference
pointers and access structure members.

Another question is about what "opaque type" means. Here
there isn't a single answer, because the term is used in
two similar but slightly different ways -

1. a type whose representation should not be accessed
outside the implementing module

2. a type whose representation can not be accessed outside
the implementing module

Obviously these two usages are related but they are
different, and that's probably the source of the confusion
here.

A third question is, how would one get an #2-style opaque
type in C. The answer there is to put only a declaration
in the header file, and define the struct in a .c file,
as for example -

/* list.h */
...
typedef struct List_struct *List;

extern List List_append(List list, List tail);
extern List List_copy(List list);
extern List List_list(void *x, ...);
...
/* list.c */
#include "list.h"

struct List_struct {
List rest;
void *first;
}

In either case the intention is that only list.c will
access the structure members, but now other code can't
access them because of where the struct itself is defined.

Note that this approach doesn't work if list.h needs to
define macros that access some structure members. In
that case we might still call List an "opaque type",
only now the meaning is more like the first meaning of
opaque type, because C doesn't have a way to allow
macro access but prevent other access.

Aug 18 '06 #9
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?
The other answers given are failrly reasonable. However, I would just
like to point out that opacity is generally focused on the undetailed
struct, and not the fact that it has been typedefed to a pointer.
I.e., the typedef struct List_T * List_T line is redundant and
unnecessary (and also going to cause C++ compilers to go into fits.)
You can simply use the expression struct List_T * instead of List_T
with no ill effect.

I.e., the pointers are derivative of the overall idea of making opaque
structs, and the additional typedef is not relevant to the opacity.

The reason I am pointing this out is that there is an alternative way
to gaining opacity through straight void * pointers. You might accept
void * pointers as your ADT handle, and simply cast it to a (struct
List_T *) inside your implementation. This works just fine, but has
the disadvantage of losing typesafety (the compiler will not warn you
when you've mixed up the handles to two different ADTs, if you declare
them both as void *, for example.) The advantage of using void *, is
that you can support a primitive kind of runtime polymorphism. I.e.,
its possible to have an array of void *'s each pointing to a different
kind of abstract data type, where even this signature can change at
runtime. Obviously in this case, the details of how exactly you would
even know what the type of each entry in such an array is what would be
interesting. This is *probably* beyond what you are interested in at
this moment, but I just thought I should point it out, since your
question was about opaque *pointers*.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 19 '06 #10

we******@gmail.com wrote:
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?

The other answers given are failrly reasonable. However, I would just
like to point out that opacity is generally focused on the undetailed
struct, and not the fact that it has been typedefed to a pointer.
I.e., the typedef struct List_T * List_T line is redundant and
unnecessary (and also going to cause C++ compilers to go into fits.)
You can simply use the expression struct List_T * instead of List_T
with no ill effect.

I.e., the pointers are derivative of the overall idea of making opaque
structs, and the additional typedef is not relevant to the opacity.
Using a typedef allows client code to know less
about a type's representation. Thus it is
relevant to how opaque the type is. Using a
typedef might be desirable or it might not
be, but it is relevant.

Aug 19 '06 #11

"pemo" <us***********@gmail.comwrote in message
news:ec**********@frank-exchange-of-views.oucs.ox.ac.uk...
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented
in C?

I read about this concept in the book "C interfaces and
implementations".

Here's an example from the book (list.h - available from the website):

#define T List_T

typedef struct T *T;
struct T {
T rest;
void *first;
};

extern T List_append (T list, T tail);
extern T List_copy (T list);
extern T List_list (void *x, ...);
.
.
and so on...

It seems the struct behind List_T is now hidden from the application
using these functions.The contents of List_T cannot be accessed (or
dereferenced?).

But I don't see why not. If I have access to the header file, wouldn't
I be able to dereference the contents of the structure? Or am I
missing the meaning of opaque?

Any answers is much appreciated.

I seem to remember that Chris Torek had plenty to say on this relatively
recently [and see his 'previously' too]. So, I'd advise you to search the
whole of c.l.c for Chris' stuff [always valuable] - Google's you best mate
here.
http://groups.google.com/group/comp....fab6b6f1?hl=en

Aug 19 '06 #12
en******@yahoo.com wrote:
we******@gmail.com wrote:
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?
The other answers given are failrly reasonable. However, I would just
like to point out that opacity is generally focused on the undetailed
struct, and not the fact that it has been typedefed to a pointer.
I.e., the typedef struct List_T * List_T line is redundant and
unnecessary (and also going to cause C++ compilers to go into fits.)
You can simply use the expression struct List_T * instead of List_T
with no ill effect.

I.e., the pointers are derivative of the overall idea of making opaque
structs, and the additional typedef is not relevant to the opacity.

Using a typedef allows client code to know less
about a type's representation.
No, the typedef has to be exposed in the header file (or possibly
somewhere else). But the typedef is just a pointer. This structure is
essentially exposed even if you don't "look" at the header file.

For example, you can say List_t x; /*... */ void * p = x; and the
compiler doesn't complain -- so this is a kind of exposure. Or more
minimally you can say sizeof (x) without trouble. Compare this with
struct List_t *x, *y, and try to do this: *x = *y, or sizeof(*x) or
sizeof(struct List_T). They both lead to compiler errors.
[...] Thus it is
relevant to how opaque the type is. Using a
typedef might be desirable or it might not
be, but it is relevant.
If you were able to somehow *hide* this typedef, and have the typedef
just magically be there, and somehow turn off its compatibility with
other pointers and sizeof(), then I would agree with you. But you
don't have this.

In fact if you want to truly "opaquify" a pointer, the way to do that,
is to put it into an opaque struct (or union).

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 19 '06 #13
en******@yahoo.com wrote:
we******@gmail.com wrote:
>chankl wrote:
>>Can anyone explain what's an opaque pointer and how it's
implemented in C?

The other answers given are failrly reasonable. However, I
would just like to point out that opacity is generally focused
on the undetailed struct, and not the fact that it has been
typedefed to a pointer. I.e., the typedef struct List_T * List_T
line is redundant and unnecessary (and also going to cause C++
compilers to go into fits.) You can simply use the expression
struct List_T * instead of List_T with no ill effect.

I.e., the pointers are derivative of the overall idea of making
opaque structs, and the additional typedef is not relevant to
the opacity.

Using a typedef allows client code to know less
about a type's representation. Thus it is
relevant to how opaque the type is. Using a
typedef might be desirable or it might not
be, but it is relevant.
Your last comment is about the only sensible thing in this whole
thread. The point about opaque pointers is that they allow
complete hiding of the implementation, thus preserving the freedom
to modify without harming the usability. Let's take an example:

/* foolib.h contains */
typedef struct foo *fooptr;

fooptr fooinit(/* various params */);
void fookill(fooptr fooid);
int fooscan(fooptr fooid);
int fooinsert(fooptr fooid, int item);
int foodelete(fooptr fooid, int item);

Note that anything that #includes foolib.h will be able to declare
a fooptr, get a value for that by calling fooinit, and then use the
system by passing that fooptr back to any functions it calls. The
user has no idea what is in a "struct foo", yet that struct will
usually have been malloced and exist in the users memory space.

This has various advantages. For one, the library can be fully
re-entrant, provided the passed in fooids are distinct. Thus no
extra code is needed for multiple instances. The library
maintainer is completely free to revise the code (but not
foolib.h), algorithms, etc. used without affecting the user code in
any way. There is no way for a user to affect the internals of the
foolib, other than by random chance probing into a struct foo, so
the library integrity is assured (as far as possible with the C
language). The actual struct foo will probably store a description
of the state of the foolib, including things related to the
initializing parameters supplied via fooinit.

Note that the actual definition of a "struct foo" occurs only
within foolib.c and is never published. Any functions, other than
those prototyped in foolib.h, will be declared as static so that
they are inaccessible from outside foolib.c. foolib.c will
probably contain no globals, nor global references, to ensure
re-entrancy.

--
"The power of the Executive to cast a man into prison without
formulating any charge known to the law, and particularly to
deny him the judgement of his peers, is in the highest degree
odious and is the foundation of all totalitarian government
whether Nazi or Communist." -- W. Churchill, Nov 21, 1943
Aug 19 '06 #14

CBFalconer wrote:
en******@yahoo.com wrote:
we******@gmail.com wrote:
chankl wrote:
>Can anyone explain what's an opaque pointer and how it's
implemented in C?

The other answers given are failrly reasonable. However, I
would just like to point out that opacity is generally focused
on the undetailed struct, and not the fact that it has been
typedefed to a pointer. I.e., the typedef struct List_T * List_T
line is redundant and unnecessary (and also going to cause C++
compilers to go into fits.) You can simply use the expression
struct List_T * instead of List_T with no ill effect.

I.e., the pointers are derivative of the overall idea of making
opaque structs, and the additional typedef is not relevant to
the opacity.
Using a typedef allows client code to know less
about a type's representation. Thus it is
relevant to how opaque the type is. Using a
typedef might be desirable or it might not
be, but it is relevant.

Your last comment is about the only sensible thing in this whole
thread. The point about opaque pointers is that they allow
complete hiding of the implementation, thus preserving the freedom
to modify without harming the usability. Let's take an example:

/* foolib.h contains */
typedef struct foo *fooptr;

fooptr fooinit(/* various params */);
void fookill(fooptr fooid);
int fooscan(fooptr fooid);
int fooinsert(fooptr fooid, int item);
int foodelete(fooptr fooid, int item);

Note that anything that #includes foolib.h will be able to declare
a fooptr, get a value for that by calling fooinit, and then use the
system by passing that fooptr back to any functions it calls. The
user has no idea what is in a "struct foo", yet that struct will
usually have been malloced and exist in the users memory space.

This has various advantages. For one, the library can be fully
re-entrant, provided the passed in fooids are distinct. Thus no
extra code is needed for multiple instances. The library
maintainer is completely free to revise the code (but not
foolib.h), algorithms, etc. used without affecting the user code in
any way. There is no way for a user to affect the internals of the
foolib, other than by random chance probing into a struct foo, so
the library integrity is assured (as far as possible with the C
language). The actual struct foo will probably store a description
of the state of the foolib, including things related to the
initializing parameters supplied via fooinit.

Note that the actual definition of a "struct foo" occurs only
within foolib.c and is never published. Any functions, other than
those prototyped in foolib.h, will be declared as static so that
they are inaccessible from outside foolib.c. foolib.c will
probably contain no globals, nor global references, to ensure
re-entrancy.Basically I agree with everything you've said here.
The points we're making are in somewhat different
realms. Technically C doesn't have opaque types,
rather it has some characteristics that allow us
to make types that we can think of as opaque.
Your comments show one way of doing this, and
list some advantages of using this approach.
I concur that this method has these kinds of
advantages.

Aug 24 '06 #15

we******@gmail.com wrote:
en******@yahoo.com wrote:
we******@gmail.com wrote:
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?
>
The other answers given are failrly reasonable. However, I would just
like to point out that opacity is generally focused on the undetailed
struct, and not the fact that it has been typedefed to a pointer.
I.e., the typedef struct List_T * List_T line is redundant and
unnecessary (and also going to cause C++ compilers to go into fits.)
You can simply use the expression struct List_T * instead of List_T
with no ill effect.
>
I.e., the pointers are derivative of the overall idea of making opaque
structs, and the additional typedef is not relevant to the opacity.
Using a typedef allows client code to know less
about a type's representation.

No, the typedef has to be exposed in the header file (or possibly
somewhere else). But the typedef is just a pointer. This structure is
essentially exposed even if you don't "look" at the header file.
When I say a typedef "allows client code to know less"
what I mean is code can be written that doesn't depend
on the types representation. Not that it _can't_ be
written to depend on the representation, but that
it _can_ be written so that it _doesn't_ depend.
That's an important property, and using typedef
enables that.
For example, you can say List_t x; /*... */ void * p = x; and the
compiler doesn't complain -- so this is a kind of exposure. Or more
minimally you can say sizeof (x) without trouble. Compare this with
struct List_t *x, *y, and try to do this: *x = *y, or sizeof(*x) or
sizeof(struct List_T). They both lead to compiler errors.
That's true but irrelevant to the point I'm making.
[...] Thus it is
relevant to how opaque the type is. Using a
typedef might be desirable or it might not
be, but it is relevant.

If you were able to somehow *hide* this typedef, and have the typedef
just magically be there, and somehow turn off its compatibility with
other pointers and sizeof(), then I would agree with you. But you
don't have this.

In fact if you want to truly "opaquify" a pointer, the way to do that,
is to put it into an opaque struct (or union).
To be technically accurate, C doesn't have opaque types.
The standard doesn't mention them, and there is no construct
in C that produces a type that is 'opaque' in the sense
that the term is used in languages that have opaque types
incorporated into the language.

Rather, what C has is ways of making types that we
can _think of_ as opaque. Using typedef is one way
of doing this. Putting a struct definition in
a source file rather than a header file is another
way. Wrapping the representation inside a struct
and using only the struct in client code is another
way. Each of these ways may offer certain advantages
or disadvantages, but none of them creates a type
that is truly opaque, only a type that is convenient
to think of as opaque. That's why using typedef
is relevant to the notion of opaque types in C.

Aug 24 '06 #16
en******@yahoo.com wrote:
we******@gmail.com wrote:
en******@yahoo.com wrote:
we******@gmail.com wrote:
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?

The other answers given are failrly reasonable. However, I would just
like to point out that opacity is generally focused on the undetailed
struct, and not the fact that it has been typedefed to a pointer.
I.e., the typedef struct List_T * List_T line is redundant and
unnecessary (and also going to cause C++ compilers to go into fits.)
You can simply use the expression struct List_T * instead of List_T
with no ill effect.

I.e., the pointers are derivative of the overall idea of making opaque
structs, and the additional typedef is not relevant to the opacity.
>
Using a typedef allows client code to know less
about a type's representation.
No, the typedef has to be exposed in the header file (or possibly
somewhere else). But the typedef is just a pointer. This structure is
essentially exposed even if you don't "look" at the header file.

When I say a typedef "allows client code to know less"
what I mean is code can be written that doesn't depend
on the types representation.
But the same would be true if you used, say, a #define to try to "hide"
the definition as well.
[...] Not that it _can't_ be
written to depend on the representation, but that
it _can_ be written so that it _doesn't_ depend.
But that's totally nonsense. If you actively avoid such direct access,
then it doesn't matter whether you've hidden the definition or not.
The point of using real language support for opacity is to have the
compiler work with you in enforcing such opacity. Some might consider
this a part of what it means to have strong typing.
That's an important property, and using typedef
enables that.
Except that this doesn't distinguish itself from #defines which can
accomplish the same thing.
For example, you can say List_t x; /*... */ void * p = x; and the
compiler doesn't complain -- so this is a kind of exposure. Or more
minimally you can say sizeof (x) without trouble. Compare this with
struct List_t *x, *y, and try to do this: *x = *y, or sizeof(*x) or
sizeof(struct List_T). They both lead to compiler errors.

That's true but irrelevant to the point I'm making.
I'm sure it is -- but it seems to me that its your point which is less
relevant to the topic of real opacity.
[...] Thus it is
relevant to how opaque the type is. Using a
typedef might be desirable or it might not
be, but it is relevant.
If you were able to somehow *hide* this typedef, and have the typedef
just magically be there, and somehow turn off its compatibility with
other pointers and sizeof(), then I would agree with you. But you
don't have this.

In fact if you want to truly "opaquify" a pointer, the way to do that,
is to put it into an opaque struct (or union).

To be technically accurate, C doesn't have opaque types.
The standard doesn't mention them, [...]
Ok, now you are slipping into Keith Thompson mode. Just because the
standard does not explicitely use the language, doesn't mean the thing
isn't there. C *DOES* contain the following: variables, a stack and a
heap (or dynamic memory pool), regardless of what the standard says
(even if the implementation of the later two are not specified).
That's because all those are general concepts that the C language has
support for, even if not spelled out in the specification. Similarly,
my computer has the ability to factor large integers even though none
of its specifications explicitely say that it can do that.

Same is true of opacity. C isn't missing opacity because it doesn't
discuss it in the standard. Opacity is merely a *property* of certain
declarations (structs and unions that are not fully specified and void
* pointers). This is a real concept because of how it dictates the
interaction between *two* programmers. If one programmer makes an
opaque type, then another cannot normally gain access to its explicit
definition, and this is enforced (more like 'supported' for void *'s)
by the compiler/language. So the two programmers don't even have to
contact each other to understand how things are supposed to be used.
On the other hand, if one is simply relying on typedef, the other
programmer can just read the header file see that its a typedef and
just go ahead and do things like handle->privateEntry (unless real
opacity via a struct or union is in there).
[...] and there is no construct
in C that produces a type that is 'opaque' in the sense
that the term is used in languages that have opaque types
incorporated into the language.
Obviously every language puts a slightly different spin on things
(compare tables in Lua with tables in TCL with Dictionaries in Python
with hashes in Perl; or coroutines in Lua versus generators in Python).
C's main weakness is that an "opaque type" can be *falsely* redefined
anyways -- but doing so, is an explicit subversion of intent, and
should not be a problem in real practice (assuming you are doing things
in good faith -- i.e., avoid the void * method, and don't ever define
any struct/union in more than one file). Other languages are likely to
have tougher enforcement, but the main concepts are the same.
Rather, what C has is ways of making types that we
can _think of_ as opaque.
If such mechanisms exist primarily in your mind, then they apply
equally to all other languages, and exposed mechanisms from any data
type anywhere. There is nothing special about typedef which
corresponds to one's "thinking". If you are just one programmer, its
not a problem at all to "think" about certain data types as being
opaque in certain contexts regardless of what the real state is --
typedef has nothing to do with this.

There is a big difference between opacity enforced by a compiler and
opacity conceptualized through convention. And this is most critically
seen as the number of developers on a project increases.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Aug 24 '06 #17

we******@gmail.com wrote:
en******@yahoo.com wrote:
we******@gmail.com wrote:
en******@yahoo.com wrote:
we******@gmail.com wrote:
chankl wrote:
Can anyone explain what's an opaque pointer and how it's implemented in
C?
>
The other answers given are failrly reasonable. However, I would just
like to point out that opacity is generally focused on the undetailed
struct, and not the fact that it has been typedefed to a pointer.
I.e., the typedef struct List_T * List_T line is redundant and
unnecessary (and also going to cause C++ compilers to go into fits.)
You can simply use the expression struct List_T * instead of List_T
with no ill effect.
>
I.e., the pointers are derivative of the overall idea of making opaque
structs, and the additional typedef is not relevant to the opacity.

Using a typedef allows client code to know less
about a type's representation.
>
No, the typedef has to be exposed in the header file (or possibly
somewhere else). But the typedef is just a pointer. This structure is
essentially exposed even if you don't "look" at the header file.
When I say a typedef "allows client code to know less"
what I mean is code can be written that doesn't depend
on the types representation.

But the same would be true if you used, say, a #define to try to "hide"
the definition as well.
Yes, that is another technique, although using typedef
is usually better.
[...] Not that it _can't_ be
written to depend on the representation, but that
it _can_ be written so that it _doesn't_ depend.

But that's totally nonsense. If you actively avoid such direct access,
then it doesn't matter whether you've hidden the definition or not.
Suppose the type in question is an unsigned int. If there is no
typedef, then client code declaring variables of the type
would use

unsigned xyz;

If later we wanted to change the representation to be
a pointer rather than an unsigned, then client code
would need to be changed to accommodate the new type.

If typedef had been used, no client code would need to
be changed; the client code doesn't depend on what
underlying type is used to represent the type name.
The point of using real language support for opacity is to have the
compiler work with you in enforcing such opacity. [...]
That is one aspect of opaque types but not the only
aspect.
That's an important property, and using typedef
enables that.

Except that this doesn't distinguish itself from #defines which can
accomplish the same thing.
Perhaps you need to review the differences between

typedef struct foo_struct *Foo;

and

#define Foo struct foo_struct *

which, although they both define Foo, cannot be
used interchangeably.
For example, you can say List_t x; /*... */ void * p = x; and the
compiler doesn't complain -- so this is a kind of exposure. Or more
minimally you can say sizeof (x) without trouble. Compare this with
struct List_t *x, *y, and try to do this: *x = *y, or sizeof(*x) or
sizeof(struct List_T). They both lead to compiler errors.
That's true but irrelevant to the point I'm making.

I'm sure it is -- but it seems to me that its your point which is less
relevant to the topic of real opacity.
You have a narrow view of what it means to program
using "opaque types". You're welcome to your view,
but it isn't the only view.
[...] Thus it is
relevant to how opaque the type is. Using a
typedef might be desirable or it might not
be, but it is relevant.
>
If you were able to somehow *hide* this typedef, and have the typedef
just magically be there, and somehow turn off its compatibility with
other pointers and sizeof(), then I would agree with you. But you
don't have this.
>
In fact if you want to truly "opaquify" a pointer, the way to do that,
is to put it into an opaque struct (or union).
To be technically accurate, C doesn't have opaque types.
The standard doesn't mention them, [...]

Ok, now you are slipping into Keith Thompson mode. [...]
Oh, a compliment - thank you! Would I be returning the
favor if I said you were slipping into websnarf mode?
Rather, what C has is ways of making types that we
can _think of_ as opaque.

If such mechanisms exist primarily in your mind, then they apply
equally to all other languages, and exposed mechanisms from any data
type anywhere. There is nothing special about typedef which
corresponds to one's "thinking". [...]
If you say there isn't for you, I have no problem
with that. Not everyone shares your viewpoint, however.
There is a big difference between opacity enforced by a compiler and
opacity conceptualized through convention. And this is most critically
seen as the number of developers on a project increases.
I wasn't arguing the relative merits, only saying that
using typedef is relevant to the notion of opaque types
in C. Using typedef facilitates one kind of advantages;
using hidden struct definitions facilitates another kind
of advantages. Both kinds relate to opaque types.

Aug 24 '06 #18
On Sat, 19 Aug 2006 10:01:35 -0400, CBFalconer <cb********@yahoo.com>
wrote:
<snip>
Your last comment is about the only sensible thing in this whole
thread. The point about opaque pointers is that they allow
complete hiding of the implementation, thus preserving the freedom
to modify without harming the usability. Let's take an example:

/* foolib.h contains */
typedef struct foo *fooptr;

fooptr fooinit(/* various params */);
<snip etc.>
This has various advantages. For one, the library can be fully
re-entrant, provided the passed in fooids are distinct. Thus no
extra code is needed for multiple instances. The library
That is not an advantage for this technique; it is equally possible
with nonopaque types. In both cases, as you indicate later, it
requires some care, and is not an inherent property.
maintainer is completely free to revise the code (but not
foolib.h), algorithms, etc. used without affecting the user code in
In theory. In practice, at least if foolib is substantial in
functionality and significantly used, at least some clients tend to
become dependent on properties additional to those in the (rather
limited) C specification of the interface -- and get very upset if
broken by an implementation change. However, even being
_substantially_ free to change the library without _any_ change to
clients is A Good Thing (tm) and usually Worth It (tm).

Aside: who was it used to trademark words like this? I've forgotten.
any way. There is no way for a user to affect the internals of the
foolib, other than by random chance probing into a struct foo, so
the library integrity is assured (as far as possible with the C
language.) <snip>
Agree, with the sadly-too-important qualification you gave, plus
another: if foolib depends on some process (or wider) resource(s) also
accessible to the client, or for that matter barlib. Obvious and
too-common examples are things like: using up memory; (mis)using fds
or other capabilities like sockets; changing the locale, or working
directory, or alarm timer(s). But again, pretty-good isolation well
short of perfect is still a good deal better than nothing.
- David.Thompson1 at worldnet.att.net
Aug 28 '06 #19

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

12 posts views Thread by Ellarco | last post: by
19 posts views Thread by Capstar | last post: by
2 posts views Thread by jashugun | last post: by
3 posts views Thread by Ernesto Bascón | last post: by
27 posts views Thread by Nate Eldredge | last post: by
reply views Thread by NPC403 | last post: by
1 post views Thread by UniDue | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.