This question is a test of concept of the question in Why is it valid to define a type as pointer to an undefined struct in C?
I know that it is not a useful program, please abstain to say "you didn't define this and that". The discussion was about pointer aritmethic on an opaque type. Sorry for bothering too many people, but the answers can be useful anyway.
This program:
struct st1 {
int a,b;
};
struct st2;
typedef struct st2 *foo;
typedef struct foo *bar;
void main(void) {
struct st1 *net=0;
foo ft1=0;
bar test=0;
net++;
ft1++;
test++;
}
when compiled with gcc gives the following:
pc:~$ cc tmp2.c
tmp2.c: In function 'main':
tmp2.c:17:6: error: increment of pointer to unknown structure
ft1++;
^
tmp2.c:17:3: error: arithmetic on pointer to an incomplete type
ft1++;
^
tmp2.c:18:7: error: increment of pointer to unknown structure
test++;
^
tmp2.c:18:3: error: arithmetic on pointer to an incomplete type
test++;
^
I would like to understand better what is happening here, because of course pointer aritmethic is a bit difficult when not knowing what the pointer points to...
The main use of a pointer to an “opaque type” is merely to receive it from a library routine (or similar) routine and pass it on to other routines. Thus, one does not need to perform arithmetic on such types.
For example, one might call a routine that says “Get ready to read stuff from this file. It will be formatted using format X, with sub-elements of length Z, and I am going to calculations P, Q, and R with them.” In response, the routine sets up some buffers, prepares some tables to assist in parsing, and calculates some numbers needed for the calculations P, Q, and R.” That routine returns a pointer to you.
To you, that pointer is opaque; you do not know what structure it points to. To the routine, it is a very specific structure, one defined in the library and shared with other library routines.
Later, you call another routine that does the actual work, and you pass it the pointer. That other library routine knows the definition of the structure, so it is able to use everything in it.
One advantage of this is that future versions of the library can change the definition of the structure. Since your program never sees the definition, it cannot rely on it. So, if the library wants to add features or change how things work internally, it can alter the definition of the structure. Then your source code does not need to be recompiled. When it is linked with a new version of the library, the new library will use the new structure.
You are missing the definition of
struct st2
. All you have is a declaration telling the compiler that such a struct exists, but you did not tell the compiler what the struct members are, so the compiler does not know how to do any operations that depends on knowing the size or the members of the struct. When you doft1++
, you are telling the compiler to increase theft1
pointer by the size of the structst2
, which is unknown.The same thing applies for
struct foo
.All started with a comment to a reply on this answer: Why is it valid to define a type as pointer to an undefined struct in C? and there was really no need to build such a mess. Anyway I reply to my question to better clarify and give more information. I am not a C guru, so my terminology can be imprecise.
The original question was why a C program declaring a pointer to an inexistent structure can compile correctly. To make it short, it is because this way it is possible to use opaque types, types which can be used without knowing much about them (so the programmer can not fiddle with their contents). It is a nice C trick, used especially in libraries; C language is not brilliant about identifiers visibility, and this trick overcomes in some way this limitation.
One of the answers of the original question stated that such pointers (those to opaque types) are not really different from other pointers. This statement is not entirely true, and my comment ("what about pointer arithmetic?") only intended to ring an alarm.
Well, the answer to the original question is that it is not an error to declare (via typedef) a pointer to an undeclared structure, and neither is an error to declare variables having that type. But it is an error to try to use such type in certain manners (the ones that require knowledge about the real data behind the type).
Honestly, the C language behavior is not the maximum of coherency, and the only reason that comes to my mind for it, is because you can declare opaque types. These opaque types are useful only in a context of separate compilation units, especially libraries. Again, the C way of doing separate compilation units is specific to C, and it is not perfect.
By stating that "declarations must then be defined", some subtle wrong thought arises. Do we want opaque data? Then incomplete declarations must NOT be completed. Therefore, certain operations are not possible on pointers to opaque data.
In the program posted in the top question of this page, there is a typedef declaration referring to a totally inexistent structure ("struct foo"). This is another point: OK for letting typedefs to refer to incomplete structures, but referring to inexistent ones is even more strange. Surely there must be a good reason: hey, C is C.
You have informed the compiler that you have a
struct st2
in the program by declaring it, but have not defined it then and there. That sort of promised the compiler that its definition will appear later.However you have not defined it anywhere.
Read here about the difference between a declaration and definition.
Think along the lines of a function prototype.
Like
You say a function
fun
returningvoid
and taking anint
is located somewhere. And if you don't call this function in your program, no harm is done.But if you do call it, you must have it defined somewhere, like
The case with
struct
here is similar. Had you not used a variable of typestruct st2
(andstruct foo
) or itstypedef
-ed names, there wouldn't have been any errors.But if you do use them, they must be defined so the compiler can know what it should do.
Given the code
struct st2
can be considered an "opaque structure", andfoo
is a pointer to an opaque structure. Per Wikipedia:Without the structure details, as you've noticed it's not possible to do pointer arithmetic.