I think so. Even with a compiled library distributed with a header file but no source, the header file needs to forward declare something like 'typedef struct foo FOO;' So (unless there's some clever trick I've missed) you can always tell it's a struct but not necessarily see the definition.
There is a point, perhaps a little specious, that you put a module's data structures behind a typedef so the interface doesn't change if it changes from a simple data type to a struct. Probably doesn't happen too often.
The perfect C object-oriented-style interface is FILE* from stdio.h. A FILE is a structure full of operating-system-specific file information but you never have to see it or worry about what's in it, you just use the functions.