What is strong typing in c? - c

I have read this code snippet somewhere but i am not able to understand it's meaning.
/** Use strong typing for ODP types */
#define odp_handle_t struct {} *
What is significance of above code snippet?

This code snippet defines the symbol odp_handle_t which represents an opaque handle to a resource. It's opaque because it's a pointer to an empty struct. The thing that it's pointing to is not exposed to the user. It's called a handle because it does not point directly to the resource, it just identifies it. The internal implementation knows how to use this handle to access the required resource. This helps maintain independence between the client code and the implementation of the API. Finally, the strong typing part comes from the fact that it's a pointer to a type (the empty struct) as opposed to a void pointer.

That is just some nonsense code not really related to strong typing. It appears to be some non-standard way of declaring a pointer to incomplete type, but it is not valid C.
#define odp_handle_t struct {} *
odp_handle_t x; // will not compile, struct has no members
I believe this is yet another pointless gcc extension. Also, hiding away pointers behind typedefs is always a very bad idea.
There is no reason why you can't declare your pointer to incomplete/opaque type with pure standard C, and you can do so without hiding pointers behind typedefs:
h file
typedef struct odp_handle_t odp_handle_t;
c file
struct odp_handle_t
{
// have to put struct members in here
};
caller c file
odp_handle_t *pointer_to_incomplete_type;

Related

When does it make sense to use a struct without a typedef?

Structs in C declare a data structure that associates different data types into a contiguous piece of memory.
Typedefs are a way to create user-defined data type names. This is useful for many applications including <stdint.h>
Structs seem to be exclusively used with typedefs. It seems like the default behaviour of defining a struct should also define a typedef.
Why would I ever want to define struct without also using a typedef?
It's a matter of personal preference, possibly imposed onto other people working on the same project as a convention. For instance, the Linux kernel coding style guide discourages the introduction of new typedefs in no uncertain terms.
Though I don't necessarily agree with everything in that guide, some of which seems silly (for instance vps_t a; example could be virtual_container_t a;: the issue hinges on the cryptic name that is chosen for typedef more than the existence of the typedef), in my TXR language project, here are some raw stats:
txr$ git grep '^typedef struct' '*/*.[ch]' '*.[ch]' | wc
25 91 839
txr$ git grep '^struct' '*/*.[ch]' '*.[ch]' | wc
135 528 4710
Lines of code beginning with struct outnumber typedef struct lines by a factor of 5.4!
The union/tag namespace feature of C means that you can have a variable called foo in the same scope as a struct foo without a clash, which is useful. This extra namespace gives us an opportunity not to pollute the regular identifier namespace with user-defined type names, which improves hygiene.
The cost is that we have to type struct foo instead of just foo in declarations.
It makes particular sense if you have experience with languages in which class/type names do not intrude into the lexical variable namespace, like Common Lisp.
The above code base, though, compiles as C++, so that throws a bit of a monkey wrench into it. In C++, struct foo defines foo as a type, which can be referenced in the ordinary namespace.
Another reason is that there is some clarity. When we see a declaration like:
struct foo x;
we know that x is a structure, whereas
foo x;
could be anything; it could be typedef double foo. Sometimes we go for that kind of abstraction. When you want to hide how something is implemented, reach for typedef. However, typedef doesn't provide perfect abstraction.
Also, if we see:
struct foo f;
struct bar b;
we know that these are necessarily different, incompatible types. We do not know that given:
foo f;
bar b;
They could both be typedefs for the same structure or for int for all we know.
If you typedef pointer types, but the code dereferences them, it looks pretty silly:
foo x = get_foo();
char *fname = x->name; /* what? */
That kernel coding style document has this to say about the above: In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.
Not using typedef for structures has as much to do with some of the hygiene of using the tag namespace, as it has to do with avoiding typedef as such: keeping the code explicit, and reserving typedef for situations in which we actually need a proper abstraction.
Structs seem to be exclusively used with typedefs.
This is a mistaken impression. Structs are frequently used without typedefs, and I personally prefer that. There are numerous struct types declared and used, without built-in typedefs, by the C standard library and POSIX standard library extension functions, for example.
It seems like the
default behavior of defining a struct should also define a typedef.
In C++, it effectively does.
Why would I ever want to define struct without also using a typedef?
Why would you ever want to define a struct with a typedef? Using a (tagged) structure type via the struct keyword and its tag clarifies what kind of type it is, and enables you to determine quickly by eye whether two types are the same. On the other hand, a typedefed alias can represent any type at all, and there can be multiple such aliases for the same type.
There are some good and appropriate uses of typedef, but there are a lot of other uses whose propriety is a code style consideration. Myself, I strongly prefer styles that minimize use of typedef.
typedef is just a convenience to allow you to refer to your struct without explicitly stating struct MyStruct every time you refer to it.
Some actually prefer this explicitness, making it clear you're working with a user-defined type.
I never typedef my structs so that they can be "extern" declared in other headers easier.
You ask: Why would I ever want to define struct without also using a typedef?
It depends what you mean by 'define a struct'. Not all uses of struct are to define named types.
For example you could define a variable via
struct
{ double a, b;
} dbls = { -1.0, 1.0};
Then dbls.a etc makes sense, but there is no named type.
Similarly in an anonymous union you might have
struct ructT
{ union
{ struct { int a; int b; } ints;
struct { float a; float b; } floats;
};
};
Here one has defined a type struct ructT but the inner structs are unnamed.
In each of these cases if one was to insist on typedefs, there would be more names to dream up, and more code to type.
typedef isn't just about saving a few keystrokes - it's about abstracting away implementation details of the underlying type. IOW, if you provide a typedef name for a struct type, you should also provide a complete API for setting and accessing members, formatting for output, allocating, deallocating, etc. You're hiding the "struct"-ness of the type from whomever is using it. Think about the FILE type in the standard library - that's a typedef name, usually for some implementation-specific structure. However, you never access any element of a FILE type directly - you just pass FILE * objects to various functions (fprintf, fread, feof, ferror, etc.) that hide the implementation from you.
If you're expecting the user of the type to explicitly access members with the . or -> operators, then don't create a typedef name for it - just leave it as struct whatever. Otherwise you create a "leaky" abstraction, which creates heartburn down the line.
Similar rule for pointer types - don't hide the "pointer"-ness of a type behind a typedef unless you're willing to create a full API to abstract away pointer operations as well.

sizeof error : incomplete type is not allowed

I have several C source and header files, with a .h file for each ADT.
One of them is called Tournament. When I try to malloc memory for tournament inside tournament.h no problem happens, but when I do it in a different c file it gives me the following error
"incomplete type is not allowed"
Here is the way tournament is defined in tournament.h
typedef struct tournament_t *Tournament;
ps: some people say it's a bad thing to typedef a struct but I have to do it since the instructors want it.
And this is how it is in tournament.c and I have no problems with it
struct tournament_t
{
//fields
};
Tournament tournamentCreate()
{
Tournament new=malloc(sizeof(*new));
if(!new)
{
return NULL;
}
//I don't get any error here
}
However, in a file called chess.c, this is what happens:
#include "tournament.h"
static Tournament copyTournament(Tournament tournament)
{
if (!tournament) {
return NULL;
}
Tournament copy = malloc(sizeof(*copy));//here I get the error
if (!copy)
{
return NULL;
}
}
PS: the last function has to be static because again the instructor wants it to be.
If you need any more information to solve it, please tell me.
typedef struct tournament_t *Tournament; serves as a forward declaration of the struct. At this point in the header file, this contents of the struct is unknown to the compiler. It means that you need to write the struct definition elsewhere or the struct will rename unknown - an incomplete type.
You then place the struct definition in tournament.c. This means that the struct contents are now visible to the compiler inside that translation unit. Translation unit meaning that .c file and all the headers it includes.
This in turn means you are free to use the struct members inside tournament.c. But they will not be visible to chess.c. Because it is a different translation unit. All it can see is the forward declaration in the header, so it remains an incomplete type to chess.c.
If you had written the typedef as typedef struct tournament_t Tournament; without the pointer declaration, then chess.c wouldn't be able to even declare objects of this type, because it doesn't know how the struct is built. It can however declare pointers to an object of incomplete type - you can have a pointer without knowing the details of what it points at.
This is all likely by design, this method is known as "opaque type" and is how you design private encapsulation in C, to prevent the rest of the program from accessing members of a struct.
some people say it's a bad thing to typedef a struct but I have to do it since the instructors want it.
Using typedef or not in combination with structs is 100% subjective coding style and there's no right or wrong there. However, using pointers together with typedef is often problematic, since it can trick the programmer into thinking they have a normal object and not a pointer. In your cases, it tricks you into believing you have access to the struct.
Since it's an incomplete type you can't declare an object of it outside tournament.c. Nor can you use sizeof on such an object. That's what the compiler error is about.
You should solve this by having tournament.h providing a function that copies objects, which in turn should be implemented in tournament.c. Note how "opaque type" is forcing you to do proper program design, instead of having non-related code in some other unrelated file doing things it shouldn't.

typedef struct in header and dereference pointer to incomplete type

I'm quite rusty in C, but I think I'm having issues understanding the proper usage of using typedefs in headers, defining the actual struct's structure in the implementation file, and then using the struct in a third file.
I wrote a queue data-structure that has a type defined as such:
typedef struct queue
{
int count;
qnode_t *head;
qnode_t *tail;
} queue_t;
Where qnode_t is a struct that's only used within the queue's implementation file.
Within my header I have this:
typedef struct queue queue_t;
When using this queue_t type within another file I'm attempting to get the queue's length like this:
queue_t *work_queue;
...
int length = work_queue->count;
However, on that line where I'm looking up count I get the compiler error:
dereferencing pointer to incomplete type
I've been doing a lot of research about how to properly define types in C, but I think I just keep confusing myself more and more instead of getting clarity since many examples are either conflicting with other resources or are too simplified for me to put to practical use.
Would I be getting this error because the 'count' variable within the struct isn't defined there? If this is the case, then can I define the struct in BOTH the implementation and header? If so, can the header only have the count variable defined since the head & tail should be hidden/private? (I miss OOP) Should I just be making another function that takes a queue_t* and returns its length as size_t?
you can only dereference defined types, not declared types.
Type declarations are useful to type-check opaque pointers, but
object fields are not visible, cannot be accessed. You need to move the typedef into the header
to access fields of your queue object.
Edit: from the questions/answers below:
Yes, two identical struct definitions are seen as the same typedef. You could omit fields if you never had both definitions in the same source file, but don't do it, that leads to bugs and maintenance confusion. Better to use a naming convention eg names starting with underscores are internal.
The convention is to define the struct in the header then include the same header in the implementation file. This keeps the published layout in sync with the implementation
It is not possible in C to dereference any pointer unless the compiler has access to complete information about the type of what is pointed at. For struct pointers, that means a complete struct definition is needed.
So, when compiling the code that is complaining about an incomplete type, the compiler needs to have visibility of the complete definition of the struct type, not just the typedef of the pointer.

Why making an empty struct a new typedef and using it as a pointer type?

I have a header and a sample application using this header, all in C, I get almost all the logic of this software except for this; this the interesting part of the header:
struct A;
typedef struct A A;
in the C application this A is only used when declaring a pointer like this
A* aName;
I'm quite sure that this is a solution for just including A in the scope/namespace and give just a name to a basically void pointer, because this kind of pointer is only used to handle some kind of data, it is more like some namespace sugar.
What this could be for?
You're correct that it's like a void pointer, in that void is an incomplete type, and in this file A is also an incomplete type. About all you can do with incomplete types is pass around pointers to them.
It has one advantage over void* in this file, that it's a different and incompatible type from some other bit of code that has done the same thing with B. So you get a bit of type safety. If A is windowHandle and B is jpgHandle, then you can't pass the wrong one to a function.
It has an advantage over void* in the .c file that defines the functions that accept an A* -- that file can contain a definition of struct A, and give A whatever members it wants, that the first file doesn't need to know about.
However, you say there are no other mentions of A in any header file, which means there are no functions that accept or return it. You also say that the only use of A in your source file is to declare pointers -- I wonder where the values of those pointers come from, if any.
If all that happens if that someone defines an uninitialized A* and never uses it, then clearly this is a remnant of some old code, or the start of some code that never got written, and it shouldn't be in the file at all.
Finally, if the real type is called something a bit less stupid than A, then the name might give a clue to its use.
I assume struct A is a forward declaration. It most likely is defined in one of the .c-files.
Doing so struct A's members are private to the module defining it.
This is an example of an opaque pointer, which is useful for passing handles. See http://en.wikipedia.org/wiki/Opaque_pointer for some further info. What may be interesting here from a C++ perspective, is the notion that you can define a class with a member that is a pointer to an (as yet) undefined struct. Although this struct is thus not yet defined in the header, in some later cpp implementation this struct is given body, and the compiler does the rest. This strategy is also called the Pimpl idiom (more of which you will find LOTS on the internet). Microsoft discusses it briefly at http://msdn.microsoft.com/en-us/library/hh438477.aspx.

foward typedef structures

gcc 4.4.4 c89
I have this in my header file.
port.h
struct struct_tag;
int initialize_ports(struct_tag *port);
In my implemenation file I have this:
port.c
typedef struct struct_tag {
int port_id;
} Port_t;
And in my driver.h file, I have the following:
#include "port.h"
int initialize_ports(struct_tag *port)
{
port = malloc(sizeof *port);
/* do checking here */
}
I have forward declared the structure, as I want to hide the internal elements.
However, I am getting the following error on my initialize_ports in the header file:
expected ‘)’ before ‘*’ token
I am just wondering how can I forward declare and be able to pass the structure as a parameter?
Many thanks for any advice,
You should use:
int initialize_ports(struct struct_tag *port);
^^^^^^
Also, forward declarations give you an incomplete type which you don't know the size of. If you need to allocate a struct struct_tag you need to include the full definition for it. Alternatively you could use some create_struct_tag() function if you want to make it fully opaque.
As other answers have noted, you could change struct_tag to struct struct_tag in the prototype. Another way of getting your code to compile is to write
typedef struct struct_tag struct_tag;
in place of your existing struct struct_tag; (i.e. combine the typedef with the forward definition). That then does allow you to write
int initialize_ports(struct_tag *port)
without compile failures. However, this is still not quite what you want, because the caller can neither allocate a local variable of this type, nor malloc() one - because they don't know the size.
Other answers have suggested that you should open up the definition of the structure. That's generally not the right answer - because it removes the abstraction layer you're trying to create. Much better to have functions (in the port.c, i.e. the library that does know about the internals) such as:
struct_tag *create_port(...);
void free_port(struct_tag *port)
i.e. to create and free the structures - and indeed for other operations (such as reading from / writing to the structure) too.
You'll get an error as you don't KNOW the size of "port" as all it has to go on is the forward declaration.
In summary you are best off not using a forward declaration here unless you also set a constant value that is the sizeof "struct_tag" ... You would most likely be best off just fully declaring it.
The sizeof operator is evaluated at compile time not runtime, so at the line:
port = malloc(sizeof *port);
the compiler has no information regarding the size of the structure.
Solutions include:
fully define the type in the header file.
define initialize_ports() in port.c after the struct is fully defined.
have initialize_ports() call a function defined in ports.c to get the size of Port_t at run-time.
In any case you should not define initialize_ports() in the header file driver.h unless your compiler supports the inline or _inline keyword and you use it. Such usage would however render the code non ISO C compliant, and therefore less portable, however due to C++'s standard support for the keyword, you are likely to find it as an extension in most C tool-chains that include C++ compilation, so long as you do not use excessively strict compliance options.
However the error message you are getting is for a different reason. Unlike C++ in C struct_tag alone does not represent a type (if it did, you'd not have needed the typedef!), you must use the struct keyword.

Resources