0

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...

  • Where is the definition of the structure `st2` and `foo` ? – J...S Nov 12 '17 at 16:08
  • 1
    You have *declared* the structure `st2`, but haven't actually defined it. In other words, you told the compiler that somewhere there is a structure named `st2`, but then you don't provide the actual structure itself. So `st2` is an *unknown structure*, and the types `foo` and `bar` are therefore *incomplete*. – Some programmer dude Nov 12 '17 at 16:08
  • 1
    You are hiding pointer semantics for no reason. Your typedef's aren't an abstraction, they are an obfuscation. – StoryTeller - Unslander Monica Nov 12 '17 at 16:09
  • 1
    Please post a [mcve] for future problems. There was lots of stuff in this code that either was irrelevant (`net`) or actually obfuscated the problem (typedefs). – David Grayson Nov 12 '17 at 16:11
  • there is no problem with net++, problem is with ft++ and test ++ because structure st1 is not defined anywhere. – Achal Nov 12 '17 at 16:15
  • See [Is it a good idea to typedef pointers?](https://stackoverflow.com/questions/750178/) — for which the quick answer is "No, unless perhaps you're dealing with function pointers". Both types `foo` and `bar` are not a good idea, therefore. Your code would be easier for you, and everyone else, to understand if you used `struct st2 *` in place of `foo`. Using `typedef struct foo *bar;` is just plain evil when there's a type `foo` lurking around too (that is a pointer to an unrelated type). – Jonathan Leffler Nov 13 '17 at 01:53

5 Answers5

2

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

void fun(int);

You say a function fun returning void and taking an int 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

void fun(int a)
{ ... }

The case with struct here is similar. Had you not used a variable of type struct st2 (and struct foo) or its typedef-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.

StoryTeller - Unslander Monica
  • 148,497
  • 21
  • 320
  • 399
J...S
  • 4,713
  • 1
  • 15
  • 34
1

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 do ft1++, you are telling the compiler to increase the ft1 pointer by the size of the struct st2, which is unknown.

The same thing applies for struct foo.

David Grayson
  • 71,301
  • 23
  • 136
  • 171
1

Given the code

struct st2;

typedef struct st2 *foo;

struct st2 can be considered an "opaque structure", and foo is a pointer to an opaque structure. Per Wikipedia:

In computer science, an opaque data type is a data type whose concrete data structure is not defined in an interface. This enforces information hiding, since its values can only be manipulated by calling subroutines that have access to the missing information. The concrete representation of the type is hidden from its users, and the visible implementation is incomplete.

Without the structure details, as you've noticed it's not possible to do pointer arithmetic.

Community
  • 1
  • 1
Andrew Henle
  • 27,654
  • 3
  • 23
  • 49
1

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.

Eric Postpischil
  • 141,624
  • 10
  • 138
  • 247
-2

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.

  • *"__Anyway I reply to my question to better clarify and give more information__"* - No, you edit your question to do that. Don't post an answer that doesn't answer the question. This is not a message board. – StoryTeller - Unslander Monica Nov 12 '17 at 20:19
  • @StoryTeller: I think this post does answer the question, more or less as the other answers do. And I posted an answer instead of editing the question because, after all, answers do answer and questions do question; This last post is an answer, not a question. – linuxfan says Reinstate Monica Nov 13 '17 at 05:25