Summary of the usage of C++ typdef

This article is a direct copy of the article of other people's blog, invaded and deleted, the source of the article:

https://blog.csdn.net/sheldon761642718/article/details/51888370

The first and fourth purposes

Use one:

Define an alias for a type, not just simple macro substitution. Can be used to declare multiple objects of pointer type at the same time. For example:
char* pa, pb; // this is mostly not what we intended, it just declares a pointer to a character variable, 
// and a character variable;
the following works:
typedef char* PCHAR; // generally uppercase
PCHAR pa, pb; // It is feasible, and two pointers to character variables are declared at the same time.
Although:
char *pa, *pb;
is also feasible, but it is relatively not intuitive to use the form of typedef, especially where a large number of pointers are required, The typedef way is easier.

Use two:

Used in old C code (specifically, how old is not checked) to help struct. In the previous code, when declaring a new struct object, you must bring the struct, that is, the form is: struct structure name object name, such as:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;

In C++, you can directly write: structure name object name, namely:
tagPOINT1 p1;

It is estimated that someone thinks it is too troublesome to often write one more struct, so he invented:
typedef struct tagPOINT
{
int x;
int y;
}POINT;

POINT p1; // In this way, one less struct is written than the original method, which is more convenient, especially when it is used a lot

Perhaps, in C++, the use of typedef is not very big, but understanding it is still helpful to master the old code. After all, we may encounter code left over from earlier years in the project. .

Use three:

Use typedefs to define platform-independent types.
For example, define a floating-point type called REAL. On target platform 1, let it represent the highest precision type:
typedef long double REAL; 
on platform 2 that does not support long double, change it to:
typedef double REAL 
; On the third platform that is not supported, change it to:
typedef float REAL; 
that is to say, when cross-platform, just change the typedef itself, without any modification to other source code.
The standard library makes extensive use of this trick, such as size_t.
Also, because typedef defines a new alias for a type, not a simple string substitution, it is more robust than macros (although macros can sometimes do the same thing).

Use four:

Define a new simple alias for complex declarations. The method is: gradually replace a part of complex declarations with aliases in the original declaration, and repeat this cycle, leaving the part with the variable name to be replaced at the end, and what is obtained is the simplified version of the original declaration. Example:

1. Original declaration: int *(*a[5])(int, char*);
the variable name is a, just replace a with a new alias pFun:
typedef int *(*pFun)(int, char* );  Minimal
version of the original statement:
pFun a[5];

2. Original declaration: void (*b[10]) (void (*)());
the variable name is b, first replace the part in the right bracket, pFunParam is alias one:
typedef void (*pFunParam)()
; Replace the variable b on the left, and pFunx is alias two:
typedef void (*pFunx)(pFunParam);
The simplified version of the original declaration:
pFunx b[10];

3. The original declaration: doube(*)() (*e)[9]; 
the variable name is e, first replace the left part, pFuny is the alias one:
typedef double(*pFuny)();
then replace the right variable e, pFunParamy is the alias two
typedef pFuny (*pFunParamy)[9];
The simplified version of the original statement:
pFunParamy e;

Understand the "Right-Left Law" available for complex declarations:
starting from the variable name, go to the right first, then to the left, and reverse the reading direction when you encounter a parenthesis; after analyzing the parentheses, jump out of the parentheses, or press the right first and then the left sequence, and so on, until the entire statement has been parsed. For example:
int (*func)(int *p);
First find the variable name func, there is a pair of parentheses outside, and there is a * sign on the left, which means that func is a pointer; then jump out of the parentheses, first look at the right, and then When the parentheses are encountered, it means that (*func) is a function, so func is a pointer to this type of function, that is, a function pointer. This type of function has formal parameters of type int*, and the return value type is int.
int (*func[5])(int *);
The right side of func is an [] operator, indicating that func is an array with 5 elements; there is a * on the left side of func, indicating that the element of func is a pointer (note the * here Instead of modifying func, it modifies func[5], because the [] operator has higher precedence than *, and func is first combined with []). Jump out of the parentheses, look to the right, and encounter the parentheses again, indicating that the element of the func array is a pointer to the function type, the function it points to has a formal parameter of type int*, and the return value type is int.

Also remember 2 patterns:
type (*)(....) function pointer 
type (*)[] array pointer

Second, the two major traps

Trap one:

Remember, a typedef is a new alias that defines a type, and unlike a macro, it's not a simple string substitution. For example:
first define:
typedef char* PSTR;
then:
int mystrcmp(const PSTR, const PSTR);

Is const PSTR actually equivalent to const char*? No, it's actually equivalent to char* const.
The reason is that const gives the whole pointer itself constness, that is, the constant pointer char* const is formed.
In short, remember that when const and typedef appear together, the typedef is not a simple string substitution.

Trap two:

Typedef is syntactically a keyword for a storage class (like auto, extern, mutable, static, register, etc.), although it does not really affect the storage characteristics of the object, such as:
typedef static int INT2; //Infeasible
compilation will If it fails, it will prompt "more than one storage class specified".

The above information comes from: http://blog.sina.com.cn/s/blog_4826f7970100074k.html  Author: Chilong

Third, the difference between typedef and #define

Case number one:

Generally speaking, typedef is better than #define, especially when there are pointers. See example:

typedef char *pStr1;

#define pStr2 char *;

pStr1 s1, s2;

pStr2 s3, s4;

In the above variable definitions, s1, s2, and s3 are all defined as char *, and s4 is defined as char, which is not the pointer variable we expected. The fundamental reason is that #define is just a simple string replacement and typedef is Is to give a new name to a type.

Case 2:

The compiler will report an error in the code below, do you know which statement is wrong?

typedef char * pStr;

char string[4] = "abc";

const char *p1 = string;

const pStr p2 = string;

p1++;

p2++;

It is the p2++ error. This question reminds us once again that typedefs, unlike #defines, are not simple text substitutions. In the above code, const pStr p2 is not equal to const char * p2. There is essentially no difference between const pStr p2 and const long x, both of which are read-only restrictions on variables, but the data type of variable p2 here is defined by ourselves rather than the inherent type of the system. Therefore, the meaning of const pStr p2 is: the variable p2 of data type char* is qualified as read-only, so p2++ is wrong.

Part 4: Using typedefs to suppress bad code

Author: Danny Kalev
Compiler: MTT Studio

Original source: Using typedef to Curb Miscreant Code

Summary: Typedef declarations help create platform-independent types, and can even hide complex and incomprehensible syntax. Either way, using typedefs can bring unexpected benefits to your code, and with this article you can learn to use typedefs to avoid deficiencies and make your code more robust.

A typedef declaration, or typedef for short, creates a new name for an existing type. For example, people often use typedefs to write more beautiful and readable code. By aesthetics, we mean that typedefs hide awkward syntax constructs and platform-dependent data types, thereby enhancing portability and future maintainability. The rest of this article goes to great lengths to reveal the power of typedefs and how to avoid some common pitfalls.

Q: How do you create platform-independent data types that hide awkward and incomprehensible syntax?

A: Use typedefs to create synonyms for existing types.

Defining Memorable Type Names
  The most common use of typedefs is to create memorable type names to document the programmer's intent. The type appears in the declared variable name to the right of the ''typedef'' keyword. E.g:

typedef int size;

This declaration defines a synonym for int named size. Note that typedefs do not create new types. It just adds a synonym to an existing type. You can use size in any context where an int is required:

void measure(size * psz); size array[4];size len = file.getlength();std::vector <size> vs;

typedefs can also mask conforming types such as pointers and arrays. For example, you don't need to repeatedly define an array with 81 character elements like this:

char line[81];char text[81];

Define a typedef, whenever you want to use an array of the same type and size, like this:

typedef char Line[81]; Line text, secondline;getline(text);

Likewise, pointer syntax can be hidden as follows:

typedef char * pstr;int mystrcmp(pstr, pstr);

This takes us to the first typedef trap. The standard function strcmp() has two parameters of type 'const char *'. Therefore, it may be misleading to declare mystrcmp() like this:

int mystrcmp(const pstr, const pstr);

This is wrong, in order, 'const pstr' is interpreted as 'char * const' (a const pointer to char), not 'const char *' (pointer to const char). This problem is easy to solve:

typedef const char * cpstr; int mystrcmp(cpstr, cpstr); // now correct

Remember: whenever you declare a typedef for a pointer, add a const to the final typedef name so that the pointer itself is a constant, not an object.

代码简化
  上面讨论的 typedef 行为有点像 #define 宏,用其实际类型替代同义字。不同点是 typedef 在编译时被解释,因此让编译器来应付超越预处理器能力的文本替换。例如:

typedef int (*PF) (const char *, const char *);

这个声明引入了 PF 类型作为函数指针的同义字,该函数有两个 const char * 类型的参数以及一个 int 类型的返回值。如果要使用下列形式的函数声明,那么上述这个 typedef 是不可或缺的:

PF Register(PF pf);

Register() 的参数是一个 PF 类型的回调函数,返回某个函数的地址,其署名与先前注册的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我们是如何实现这个声明的:

int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *); 

很少有程序员理解它是什么意思,更不用说这种费解的代码所带来的出错风险了。显然,这里使用 typedef 不是一种特权,而是一种必需。持怀疑态度的人可能会问:“OK,有人还会写这样的代码吗?”,快速浏览一下揭示 signal()函数的头文件 <csinal>,一个有同样接口的函数。

typedef 和存储类关键字(storage class specifier)
  这种说法是不是有点令人惊讶,typedef 就像 auto,extern,mutable,static,和 register 一样,是一个存储类关键字。这并是说 typedef 会真正影响对象的存储特性;它只是说在语句构成上,typedef 声明看起来象 static,extern 等类型的变量声明。下面将带到第二个陷阱:

typedef register int FAST_COUNTER; // 错误

编译通不过。问题出在你不能在声明中有多个存储类关键字。因为符号 typedef 已经占据了存储类关键字的位置,在 typedef 声明中不能用 register(或任何其它存储类关键字)。

促进跨平台开发
  typedef 有另外一个重要的用途,那就是定义机器无关的类型,例如,你可以定义一个叫 REAL 的浮点类型,在目标机器上它可以i获得最高的精度:

typedef long double REAL; 

在不支持 long double 的机器上,该 typedef 看起来会是下面这样:

typedef double REAL; 

并且,在连 double 都不支持的机器上,该 typedef 看起来会是这样: 、

typedef float REAL; 

你不用对源代码做任何修改,便可以在每一种平台上编译这个使用 REAL 类型的应用程序。唯一要改的是 typedef 本身。在大多数情况下,甚至这个微小的变动完全都可以通过奇妙的条件编译来自动实现。不是吗? 标准库广泛地使用 typedef 来创建这样的平台无关类型:size_t,ptrdiff 和 fpos_t 就是其中的例子。此外,象 std::string 和 std::ofstream 这样的 typedef 还隐藏了长长的,难以理解的模板特化语法,例如:basic_string<char, char_traits<char>,allocator<char>> 和 basic_ofstream<char, char_traits<char>>。


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324524789&siteId=291194637