Typedef Struct usage details and usage summary

Article 1: The difference between typedef struct and struct

1. Basic explanation

typedef is a keyword of the C language, which is used to define a new name for a data type. The data types here include internal data types (int, char, etc.) and custom data types (struct, etc.).

There are generally two purposes for using typedefs in programming. One is to give a variable a new name that is easy to remember and clear, and the other is to simplify some more complex type declarations.

As for the subtleties of typedef, please read the following specific explanations on several issues.

2. Typedef & structure problem

When defining a structure with the following code, the compiler reported an error. Why? Could it be that C language does not allow a pointer to itself to be included in the structure? Please guess first, and then look at the following description:

typedef struct tagNode
{
 char *pItem;
 pNode pNext;
} *pNode;

Answer and analysis:

1. The simplest use of typedef

typedef long byte_4;

Give the known data type long a new name, called byte_4.

2. Use typedef in combination with structure

typedef struct tagMyStruct

 int iNum;
 long lLength;
} MyStruct;

This statement actually completes two operations:

1) Define a new structure type

struct tagMyStruct

 int iNum; 
 long lLength; 
};

Analysis: tagMyStruct is called "tag", that is, "tag", which is actually a temporary name. The struct keyword and tagMyStruct together form this structure type. This structure exists regardless of whether there is a typedef or not.

We can use struct tagMyStruct varName to define variables, but note that it is wrong to use tagMyStruct varName to define variables, because struct and tagMyStruct together can represent a structure type.

2) The typedef gave this new structure a name, MyStruct.

typedef struct tagMyStruct MyStruct;

Therefore, MyStruct is actually equivalent to struct tagMyStruct, and we can use MyStruct varName to define variables.

Answers and analysis

The C language certainly allows pointers to itself to be included in the structure. We can see countless such examples in the implementation of data structures such as the establishment of linked lists. The fundamental problem with the above code lies in the application of typedef.

According to our above explanation, we can know that the pNext domain declaration was encountered during the establishment of the new structure. The type is pNode. You must know that pNode represents the new name of the type. Then, when the type itself has not been established, the type of The new name does not exist yet, which means that the compiler does not recognize pNode at this time.

There are many ways to solve this problem:

1)、

typedef struct tagNode 
{
 char *pItem;
 struct tagNode *pNext;
} *pNode;

2)、

typedef struct tagNode *pNode;
struct tagNode 
{
 char *pItem;
 pNode pNext;
};

Note: In this example, you use typedef to give a new name to a type that has not been fully declared. The C language compiler supports this approach.

3) Standard practice:

typedef uint32 (* ADM_READDATA_PFUNC)( uint16*, uint32 );

I haven't seen this before. I personally think that Yu defines a uint32 pointer function, uint16*, uint32 are the two parameters in the function; it should be equivalent to #define uint32 (* ADM_READDATA_PFUNC)( uint16*, uint32 );

There are two common forms of struct in code: 
struct A 

//... 
};

struct 

//... 
} A; 
These are actually two completely different usages: the 
former is called "structure type definition", which means: define the structure in {} as a structure whose name is "A". 
This usage is generally in typedef: 
typedef struct tagA // deliberately give a different name as the real name of the structure 

//... 
} A; // alias of the structure.

The latter is the definition of structure variables, meaning: define a variable named "A" with the structure in {}. The structure here is called an anonymous structure and cannot be directly quoted. 
You can also create an alias for the anonymous structure through typedef, so that it can be quoted: 
typedef struct 

//... 
} A; //Define the alias of the anonymous structure as A

Part 2: The difference between struct and typedef struct in C and C++

There are three ways to define structure in C and C++.

typedef struct {

int data;

int text;

} S1;

//This method can define an S1 structure in c or c++

struct S2 {

int data;

int text;

};

// This way of definition can only be used in C++, and if used in C, the compiler will report an error

struct {

int data;

int text;

} S3;

This method does not define a structure, but defines a s3 structure variable, the compiler will memory for s3.

void main()

{

S1 mine1;// OK, S1 is a type

S2 mine2;// OK, S2 is a type

S3 mine3;// OK, S3 is not a type

S1.data = 5;// ERRORS1 is a type

S2.data = 5;// ERRORS2 is a type

S3.data = 5;// OKS3 is a variable

}

In addition, there are several ways to write variables that define the structure itself in the structure.

struct S6 {

S6 * ptr;

};

// This way of writing can only be used in C++

typedef struct {

S7 * ptr;

} S7;

// This is a definition that is wrong in C and C++

If in C, we can use such a "curve method to save the country"

typedef struct tagS8{

tagS8 * ptr;

} S8;

Part 3: struct and typedef struct

The description is divided into three parts:
1 First: 
typedef is used to define a structure type in C:
typedef struct Student
{ int a; }Stu; so when declaring variables: Stu stu1; if there is no typedef, you must use struct Student stu1; to declare that Stu here is actually an alias of struct Student. In addition, there is no need to write Student here (so you can't struct Student stu1;) typedef struct { int a; }Stu; But it is very simple in C++, directly struct Student { int a; }; So the structure type Student is defined , Direct Student stu2 when declaring variables; ======================================== = 2 Secondly:  If you use typedef in C++, it will make a difference: struct Student  int a;  }stu1;//stu1 is a variable  typedef struct Student2 

























int a; 
}stu2;//stu2 is a structure type 
that can directly access stu1.a when used,
but stu2 must first stu2 s2;
then s2.a=10;
============ ================================
3 It is enough to master the above two, but in the end we will discuss a question that does not matter much
If we write in the c program:
typedef struct
{ int num; int age; }aaa, bbb, ccc; what is this? I personally observe the understanding of the compiler (VC6), which is equivalent to typedef struct { int num; int age; }aaa; typedef aaa bbb; typedef aaa ccc; that is to say, aaa, bbb, and ccc are all structure types. Any one can be used when declaring a variable, even in C++. But what you have to pay attention to is that if the typedef keyword is written out in C++, then aaa, bbb, ccc will be three completely different objects.












Part 4: Usage of typedef struct and struct in C/C++

What is the difference between struct _x1 {...}x1; and typedef struct _x2{ ...} x2;? 

In fact, the former is the object instance x1 that defines the classes _x1 and _x1, and the latter is the category name x2 that defines the classes _x2 and _x2, 

so they are different during use. Please see Example 1. 

[Knowledge point] 

Structure is also a data type, and structure variables can be used. Therefore, like other types of variables, you must first define structure variables when using structure variables. 

The general format for defining structure variables is: 

struct structure name 



type variable name; 

type variable name; 

... 

} structure variable; 

structure name is the identifier of the structure, not the name of the variable. 

Another common format is: 

typedef struct structure name 



type variable name; 

type variable name; 

... 

} structure alias; 

Also note: In C, struct cannot contain functions. In C++, struct has been extended to include functions. 

================================================= ==================== 

Example 1: struct.cpp 

#include <iostream> 

using namespace std; 

typedef struct _point{ 

int x; 

int y; 

}point; //Define the class and give the class an alias 

struct _hello{ 

int x,y; 

} hello; //Define the class and the object at the same time 

int main() 



point pt1; 

pt1. x = 2; 

pt1.y = 5; 

cout<< "ptpt1.x=" << pt1.x << "pt.y=" <<pt1.y <<endl; 

//hello pt2; 

//pt2. x = 8; 

//pt2.y =10; 

//cout<<"pt2pt2.x="<< pt2.x <<"pt2.y="<<pt2.y <<endl; 

//hello above pt2; This line will fail to compile. Why? 

//Because hello is a defined object instance. 

//The correct approach is as follows: Use hello.x and hello.y 

hello.x = 8; 

hello.y = 10; 

cout<< "hellohello.x=" << hello.x << " hello.y=" <<hello.y <<endl; 

return 0; 

}

Chapter 5: Questions and Answers

Q:  What is the difference between using struct and typedef struct to define a structure? Why are there two ways?

struct Student 

int a; 
} stu; 
typedef struct Student2 

int a; 
}stu2;

A:

In fact, this thing is left over from the C language. Typedef can define a new composite type or give an alias to an existing type. In the C language, if you use the 
struct xxx 

}; method, you must Use struct xxx var to declare variables, and use 
typedef struct 

} to write xxx var; 
but this is no longer in C++, no matter which way you use it, you can use the second way to declare variables , This should be regarded as the dregs of the C language.

Usage summary

The first and four uses

Use one:

Define a type of alias, not just a simple macro substitution. Can be used to declare multiple objects of pointer type at the same time. For example:
char* pa, pb; // This mostly does not meet our intentions, it only declares a pointer to a character variable, 
// and a character variable; the
following is possible:
typedef char* PCHAR; // Generally use 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 unintuitive in the form of typedef, especially where a lot of pointers are needed. The typedef method is easier.

Use two:

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



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

It is estimated that someone feels that it is too troublesome to write a struct frequently, so he invented:
typedef struct tagPOINT
{ int x; int y; }POINT;


POINT p1; // This way, one less struct is written than the original method, which saves trouble, especially when it is used in large quantities

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

Use three:

Use typedef to define platform-independent types.
For example, the definition of a floating-point type called REAL, on a target platform, it represents the most accurate type:
typedef long double REAL; 
on the platform does not support long double two, read:
typedef double REAL; 
at even double 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.
This technique is widely used in the standard library, such as size_t.
In addition, because typedef is a new alias that defines a type, it is not a simple string replacement, so it is more robust than macros (although macros can sometimes be used for the above purposes).

Use four:

Define a new simple alias for complex declarations. The method is: gradually replace part of the complex declaration with aliases in the original declaration, and repeat this way, leaving the part with variable names to the end to replace, and what you get is the most simplified version of the original declaration. For example:

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

2. The original statement: void (* b [10] ) (void (*) ());
variable named b, to replace part of the right parentheses, pFunParam an alias:
typedef void (* pFunParam) ();
and then Replace the variable b on the left, pFunx is alias two:
typedef void (*pFunx)(pFunParam);
The most simplified version of the original declaration:
pFunx b[10];

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

Understand the "right-left rule" available for complex declarations:
starting from the variable name, go to the right and then to the left. When you encounter a parenthesis, you will switch the reading direction; after the analysis of the parentheses, you can jump out of the parentheses, or press the right and then left Sequence, and so on, until the entire statement is analyzed. For example:
int (*func)(int *p);
First find the variable name func, there is a pair of parentheses outside, and a * sign on the left, which means func is a pointer; then jump out of the parentheses, look at the right side first, and then Encounter parentheses, which 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 *);
On 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 elements of func are pointers (note here * Instead of modifying func, it modifies func[5]. The reason is that the [] operator has a higher priority than *, and func is combined with [] first). Jump out of this bracket, look to the right, and encounter parentheses again, indicating that the elements of the func array are pointers to function types. The function it points to has formal parameters of type int* and the return value type is int.

You can also remember 2 patterns:
type (*)(....) function pointer 
type (*)[] array pointer

Second, the two traps

Trap one:

Remember, typedef is a new alias that defines a type. Unlike macros, it is not a simple string replacement. For example:
first define:
typedef char* PSTR;
then:
int mystrcmp(const PSTR, const PSTR);

Is const PSTR actually equivalent to const char*? No, it is actually equivalent to char* const.
The reason is that const gives the entire pointer itself constant, which is to form a constant pointer char* const.
Simply put, remember that when const and typedef appear together, typedef is not a simple string replacement.

Trap 2:

Syntactically, typedef is a storage class keyword (such as 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: Red Dragon

Third, the difference between typedef and #define

Case number one:

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

typedef char *pStr1;

#define pStr2 char *;

pStr1 s1, s2;

pStr2 s3, s4;

In the above variable definition, s1, s2, s3 are 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:

In the following code, the compiler will report an error. Do you know which statement is wrong?

typedef char * pStr;

char string[4] = "abc";

const char *p1 = string;

const pStr p2 = string;

p1++;

p2++;

P2++ is wrong. This question reminds us again: Typedef is different from #define, it is not a simple text replacement. 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. They both impose read-only restrictions on variables, but the data type of variable p2 here is our own definition instead of the inherent type of the system. Therefore, the meaning of const pStr p2 is: the variable p2 whose data type is char * is restricted to be read-only, so p2++ is wrong.

The fourth part of the information: use typedef to suppress bad code

Author: Danny Kalev
compilation: MTT studio

Original source: Using typedef to Curb Miscreant Code

 

Abstract:  Typedef declarations help to create platform-independent types and can even hide complex and difficult to understand syntax. In any case, using typedef can bring unexpected benefits to your code. Through this article, you can learn to use typedef 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. The so-called beautiful, it means that typedef can hide clumsy grammatical structures and platform-related data types, thereby enhancing portability and future maintainability. Below in this article, I will do my best to reveal the power of typedef and how to avoid some common pitfalls.

Q: How to create platform-independent data types to hide clumsy and incomprehensible syntax?

A: Use typedefs to create synonyms for existing types.

Defining easy-to-remember type names 
  typedefs are used most often to create easy-to-remember type names and use it to document programmers’ intentions. 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 with the name size. Note that typedef does not create new types. It just adds a synonym for existing types. You can use size in any context that requires an int:

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

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

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

Define a typedef, whenever an array of the same type and size is used, you can do this:

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

Similarly, pointer syntax can be hidden like this:

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

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

int mystrcmp(const pstr, const pstr); 

This is wrong. In order,'const pstr' is interpreted as'char * const' (a constant pointer to char) instead of'const char *'(a pointer to constant char). This problem is easy to solve:

typedef const char * cpstr; int mystrcmp(cpstr, cpstr); // 现在是正确的

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

Code Simplification 
  The typedef discussed above behaves a bit like the #define macro, replacing synonyms with its actual type. The difference is that the typedef is interpreted at compile time, so the compiler is allowed to deal with text replacement beyond the capabilities of the preprocessor. E.g:

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

This declaration introduces the PF type as a synonym for a function pointer. The function has two parameters of type const char * and a return value of type int. If you want to use the following form of function declaration, then the above typedef is indispensable:

PF Register(PF pf);

The parameter of Register() is a callback function of type PF, which returns the address of a function with the same signature as the previously registered name. Take a deep breath. Below I show how we can achieve this declaration without typedef:

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

Few programmers understand what it means, let alone the risk of error caused by this inexplicable code. Obviously, the use of typedef here is not a privilege, but a necessity. A skeptical person may ask: "OK, would anyone write such code?", take a quick look at  the header file <csinal> that reveals the signal() function, a function with the same interface.

Typedef and storage class specifier 
  are a bit surprising. Typedef, like auto, extern, mutable, static, and register, is a storage class specifier. This does not mean that typedef will really affect the storage characteristics of objects; it only means that in terms of statement composition, typedef declarations look like variable declarations of static, extern, etc. types. The following will lead to the second trap:

typedef register int FAST_COUNTER; // 错误

The compilation fails. The problem is that you cannot have multiple storage class keywords in the declaration. Because the symbol typedef already occupies the storage class keyword, you cannot use register (or any other storage class keyword) in the typedef declaration.

Promoting cross-platform development 
  typedef has another important purpose, that is to define machine-independent types. For example, you can define a floating-point type called REAL, which can achieve the highest precision on the target machine:

typedef long double REAL; 

On machines that do not support long double, the typedef will look like this:

typedef double REAL; 

And, on a machine that doesn't even support double, the typedef will look like this: 、

typedef float REAL; 

You don't need to make any changes to the source code, you can compile this REAL type application on every platform. The only thing to change is the typedef itself. In most cases, even this small change can be achieved automatically through wonderful conditional compilation. Isn't it? The standard library makes extensive use of typedefs to create such platform-independent types: size_t, ptrdiff, and fpos_t are examples of them. In addition, typedefs like std::string and std::ofstream also hide long, incomprehensible template specialization syntax, such as basic_string<char, char_traits<char>, allocator<char>> and basic_ofstream<char , char_traits<char>>.

About the author  
  Danny Kalev  is a certified system analyst, a software engineer specializing in C++ and formal language theory. From 1997 to 2000, he was a member of the C++ Standards Committee. He recently completed his master's thesis in general linguistics with honors. In his spare time, he likes to listen to classical music, read Victorian literature, and study natural languages ​​such as Hittite, Basque and Irish Gaelic. Other interests include archaeology and geography. Danny often visits some C++ forums and regularly writes articles for different C++ websites and magazines. He also teaches programming language and applied language courses in educational institutions.

Guess you like

Origin blog.csdn.net/sempre20/article/details/112989651