In C, is it good to use typedef for a pointer?

Consider the following C code:

typedef char * MYCHAR; MYCHAR x; 

I understand that the result will be that x is a pointer of type "char". However, if an x ​​declaration must come far from the typedef command, the human code reader does not immediately recognize that x is a pointer. Alternatively, you can use

 typedef char MYCHAR; MYCHAR *x; 

What is considered the best form? Is this more than a matter of style?

+4
source share
8 answers

I would use pointer typedefs only in situations where the nature of the pointer of the resulting type does not matter. For example, the typedef of a pointer is justified when you want to declare an opaque type "handle", which is simply implemented as a pointer, but should not be used by the user as a pointer.

 typedef struct HashTableImpl *HashTable; /* 'struct HashTableImpl' is (or is supposed to be) an opaque type */ 

In the above example, a HashTable is a “handle” for a hash table. First, the user will get this descriptor from a function, say CreateHashTable and pass it, say, to a HashInsert function and the like. The user does not have to care (or even know) that the HashTable is a pointer.

But in cases where the user must understand that the type is actually a pointer and can be used as a pointer, pointer typedefs significantly confuse the code. I would avoid them. Declaring pointers explicitly makes the code more readable.

It is interesting to note that the C standard library avoids such typedefs. For example, FILE is obviously intended to be used as an opaque type, which means that the library could define it as typedef FILE <some pointer type> , instead of forcing us to use FILE * all the time. But for some reason, they decided not to.

+2
source

If the pointer should never be dereferenced or otherwise managed directly - IOW, you pass it only as an API argument - then everything is fine to hide the pointer behind the typedef.

Otherwise, it is better to make the "pointerness" type explicit.

+7
source

I don't really like typedef for a pointer, but there is one advantage. It eliminates confusion and common mistakes when you declare more than one pointer variable in a single declaration.

 typedef char *PSTR; ... PSTR str1, str2, str3; 

perhaps clearer than:

 char *str1, str2, str3; // oops 
+3
source

I prefer to leave * , it shows a pointer there. And your second example should be abbreviated as char* x; , it does not make sense.

+2
source

I also think this is a matter of style / convention. In the Apple Core Graphics library, they often “hide” the pointer and use the convention of adding “Ref” to the end of the type. So, for example, CGImage * corresponds to CGImageRef . So you still know this pointer link.

+2
source

Another way to look at this is in terms of types. A type defines the operations that are possible for this type, and the syntax for invoking these operations. From this point of view, MYCHAR is what it is. The responsibility of programmers is to know what operations are allowed on it. If it is declared as the first example, it supports the * operator. You can always name the identifier accordingly to clarify its use.

Other cases where it is useful to declare a type that is a pointer is when the parameter parameter is opaque to the user (programmer). There may be APIs that want to return the pointer to the user and expect the user to pass it back to the API at some other point. Like an opaque handle or cookie that the API will only use domestically. The user does not care about the nature of the parameter. It would be wise not to pollute the water and not reveal its exact nature by exposing * to the API.

0
source

If you look at several existing APIs, it seems that not putting pointerness in a type seems more convenient:

and possibly many others.

0
source

The API does not need to hide structure definitions and pointers behind "abstract" typedefs.

  /* This is part of the (hypothetical) WDBC- API ** It could be found in wdbc_api.h ** The struct connection and struct statement ar both incomplete types, ** but we are allowed to use pointers to incomplete types, as long as we don't ** dereference them. */ struct connection *wdbc_connect (char *connection_string); int wdbc_disconnect (struct connection *con); int wdbc_prepare (struct connection * con, char *statement); int main(void) { struct connection *conn; struct statement *stmt; int rc; conn = wdbc_connect( "host='localhost' database='pisbak' username='wild' password='plasser'" ); stmt = wdbc_prepare (conn, "Select id FROM users where name='wild'" ); rc = wdbc_disconnect (conn); return 0; } 

The above snippet compiles fine. (but he obviously doesn't bind)

0
source

Source: https://habr.com/ru/post/1486482/


All Articles