Is declaring a pointer to an undefined struct legal?

C

Chris Barts

Let's say we have a library with an opaque data type implemented as a
struct in the library's C source file. The definition of the struct
isn't duplicated in the header included by the programs that make use of
this library. Is it legal for the header and the programs that include
it to declare pointers to this struct for which no definition is in
scope and to pass those pointers into functions declared in that header?
 
R

Richard Bos

Chris Barts said:
Let's say we have a library with an opaque data type implemented as a
struct in the library's C source file. The definition of the struct
isn't duplicated in the header included by the programs that make use of
this library. Is it legal for the header and the programs that include
it to declare pointers to this struct for which no definition is in
scope and to pass those pointers into functions declared in that header?

In short, yes.

But you cannot initialise these pointers, except to null; you cannot
assign values to them unless that value is passed to you from a function
which does have a declaration for the struct type in scope; and you
cannot dereference those pointers. For an opaque type, of course, this
is precisely what you want.

Richard
 
A

Alex Fraser

Chris Barts said:
Let's say we have a library with an opaque data type implemented as a
struct in the library's C source file. The definition of the struct
isn't duplicated in the header included by the programs that make use of
this library. Is it legal for the header and the programs that include
it to declare pointers to this struct for which no definition is in
scope and to pass those pointers into functions declared in that header?

Yes, it's perfectly legal and IMO often quite useful, since only changes in
the interface require users of the interface to be recompiled, and even
better, all changes to the members of the struct are made inside the
library. The only downsides are that you can't use macros for (typically)
quicker access to struct members, and in most cases dynamic allocation is
required, so performance may suffer slightly.

Alex
 
C

Chris Barts

Richard said:
[partial snip]
Is it legal for the header and the programs that include
it to declare pointers to this struct for which no definition is in
scope and to pass those pointers into functions declared in that header?


In short, yes.

That's good to know.
But you cannot initialise these pointers, except to null; you cannot
assign values to them unless that value is passed to you from a function
which does have a declaration for the struct type in scope; and you
cannot dereference those pointers.

And all of those limits are precisely what I'd expect: Unless the
definition is in scope, there is no way to know the names of the
members, let alone their offsets into the object.
For an opaque type, of course, this is precisely what you want.

Very true.
 
C

CBFalconer

Chris said:
Let's say we have a library with an opaque data type implemented as a
struct in the library's C source file. The definition of the struct
isn't duplicated in the header included by the programs that make use of
this library. Is it legal for the header and the programs that include
it to declare pointers to this struct for which no definition is in
scope and to pass those pointers into functions declared in that header?

Yes.
 
C

Chris Barts

Alex said:
[snip]

Yes, it's perfectly legal and IMO often quite useful, since only changes in
the interface require users of the interface to be recompiled, and even
better, all changes to the members of the struct are made inside the
library.

This was precisely my thinking: It enforces complete locality of
everything within the opaque type, preventing programmers, and therefore
the library's author, from becoming wedded to implementation details.

I'm a pretty strong believer in that sort of thing.
The only downsides are that you can't use macros for (typically)
quicker access to struct members, and in most cases dynamic allocation is
required, so performance may suffer slightly.

The key word here, I believe, is 'slightly': Given the advantages stated
above, it would be rare (hopefully) that the performance edge of the
less-safe case is a deciding factor in how the library is implemented.

[semi-OT]Plus, passing a pointer into a function is typically a cheap
operation, so if the library itself is reasonably optimized the problem
is essentially solved.[/semi-OT]
 
A

Alex Fraser

Chris Barts said:
The key word here, I believe, is 'slightly': Given the advantages stated
above, it would be rare (hopefully) that the performance edge of the
less-safe case is a deciding factor in how the library is implemented.

The getc() function/macro is an obvious example of the trade-off. Most of
the time, it doesn't do very much, so if implemented as a function, the
overall overhead from the function calls can be a significant fraction of
the total time.

The performance cost of dynamic allocation/deallocation can usually be
minimised, and is less likely to be significant anyway. One thing I didn't
mention is that dynamic allocation needs explicit deallocation, which is
sometimes inconvenient. But some sort of cleanup besides deallocating the
structure is often needed anyway, so it's a bit of a moot point - the
inconvenience often exists either way.

Alex
 
D

Dave Thompson

[snip: using pointers to struct type encapsulated in module]
Yes, it's perfectly legal and IMO often quite useful, since only changes in
the interface require users of the interface to be recompiled, and even
better, all changes to the members of the struct are made inside the
library.

This was precisely my thinking: It enforces complete locality of
everything within the opaque type, preventing programmers, and therefore
the library's author, from becoming wedded to implementation details.

I'm a pretty strong believer in that sort of thing.
One warning: s/preventing/discouraging/ . Some people will still poke
around in your source, or hex-dump the data, or disassemble your code,
and find and use things you wanted to keep hidden. And some people
will occasionally perhaps even accidentally do "dirty" things that
cause dependencies -- like, say, memcpy'ing 32 bytes to a savearea and
later memcpy'ing it back and assuming that's enough. (I speak from
experience on both sides of this fence.)

Using 'struct hidden *' is a very good start, but _also_ document
clearly that you intend the type to be opaque -- and hope that you
either persuade users you are right to do so, or are able to ignore
the anguished screams that do arise.
- David.Thompson1 at worldnet.att.net
 
F

Flash Gordon

Dave said:
[snip: using pointers to struct type encapsulated in module]
Yes, it's perfectly legal and IMO often quite useful, since only changes in
the interface require users of the interface to be recompiled, and even
better, all changes to the members of the struct are made inside the
library.

This was precisely my thinking: It enforces complete locality of
everything within the opaque type, preventing programmers, and therefore
the library's author, from becoming wedded to implementation details.

I'm a pretty strong believer in that sort of thing.

One warning: s/preventing/discouraging/ . Some people will still poke
around in your source, or hex-dump the data, or disassemble your code,
and find and use things you wanted to keep hidden. And some people
will occasionally perhaps even accidentally do "dirty" things that
cause dependencies -- like, say, memcpy'ing 32 bytes to a savearea and
later memcpy'ing it back and assuming that's enough. (I speak from
experience on both sides of this fence.)

People will always find ways around if they really want to. One just has
to try to provide functions to do all the things people are likely to
want to do, such as copying the structure if that is a sensible thing to
allow.
Using 'struct hidden *' is a very good start, but _also_ document
clearly that you intend the type to be opaque -- and hope that you
either persuade users you are right to do so, or are able to ignore
the anguished screams that do arise.

Also state explicitly that anything bypassing your interface *will* be
broken by subsequent releases.
 

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,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top