Tag vs. Type Names

http://www.embedded.com/electronics-blogs/programming-pointers/4024450/Tag-vs-Type-Names

Tag names in C 

In C, the name s appearing in:

struct s
{
  ...
};
 

s is a tag. A tag by itself is not a type name.
If it were, then C compilers would accept declarations such as:

s x;      // error in C
s *p;     // ditto

But they don't. You must write the declarations as:

struct s x;  // OK
struct s *p;  // OK

The combination of struct and -in that order- is called an elaborated type specifier. 

The names of unions and enumerations are also tags rather than types. For example:

enum day 
{ 
  Sunday, 
  Monday, 
  ... 
};


day today;          // error
enum day tomorrow;  // OK    

Here,enum day is the elaborated type specifier. 

For the most part, C does not permit different entities to have the same name in the same scope.
For example, when these two declarations appear in the same scope:

int status();     // function
int status;      // object

the compiler will flag the second one as an error.
But C treats tags differently than it does other identifiers.
C compilers hold tags in a symbol table that's conceptually,
if not physically, separate from the table that holds all other identifiers.
Thus, it's possible for a C program to have both a tag and an another identifier
with the same spelling in the same scope.

For example, C compilers will accept both:

int status();        // function
enum status { ... };    // enumeration

in the same scope. They will even accept: 

struct s s;

which declares object s of type struct s.
Such declarations may not be good practice, but they are C.

Tags and typedefs

Many programmers prefer to think of struct tags as type names,
so they define an alias for the tag using a typedef.
For example, defining:

struct s
{
...
};
typedef struct s T;

lets you use T in place of struct s, as in:

T x;    // OK
T *p;    // OK

A program cannot use T as the name of both a type and an object
(or a function or enumeration constant), as in:

T T; // error

The tag name in a struct, union, or enum definition is optional.
Many programmers fold the struct definition into the typedef
and dispense with the tag altogether, as in:

typedef struct
{
...
} T;

This works well, except in self-referential structures containing pointers
to structures of the same type. For example:

struct list_node
{
  ...
  struct list_node *next;
};

defines a struct called list_node, which contains, among other things, a pointer to another list_node.
If you wrap the struct definition in a typedef and omit the tag, as in:

typedef struct
{
  ...
  list_node *next; // error
} list_node;

the compiler will complain because the declaration for membernext refers to list_node before list_node is declared.
With a self-referential struct, you have no choice but to declare a tag for the struct.
If you prefer to use a typedef name thereafter, you must declare both the tag and the typedef.
Many programmers follow naming conventions suggested by Kernighan and Ritchie.[1]
In the first edition of their book, they use a short, somewhat cryptic,
identifier for the tag, and a longer uppercase identifier for the typedef, as in:

typedef struct tnode
{
  ...
  struct tnode *left;
  struct tnode *right;
} TREENODE;

For the second edition, they changed TREENODE to Treenode.[2]

I've never understood why they use different names for the tag
and the typedef when one name will do just fine:

typedef struct tree_node tree_node;

What's more, you can write this definition before,
rather than after, the struct definition, as in:

typedef struct tree_node tree_node;
struct tree_node
{
    ...
    tree_node *left;
    tree_node *right;
};


You need not use the keyword struct in declaring members,
such as left and right, that refer to other tree_nodes.

http://www.cplusplus.com/forum/beginner/15967/

In C, a struct identifier has its own namespace,
separate from the regular function and variable namespace.

Hence, in C you must use the word "struct" before structure names:

struct Point
{
    int x;
    int y;
};

void LineTo( struct Point pt );  // This is C

In C++, the structure name is also placed in the regular namespace. So you could say:

struct Point
{
    int x;
    int y;
};

void LineTo( Point pt );  // This is C++ 

Long before C++ came along, people wanted to be able to get rid of the struct keyword also.
Along to the rescue came 
typedef, which declares type aliases.

struct Point
{
    int x;
    int y;
};
typedef struct Point Point;

void LineTo( Point pt );  // This is C

The two definitions can be combined:

typedef struct Point
{
    int x;
    int y;
} Point;

void LineTo( Point pt );  // This is C 

In C/C++ hackish circles, the structure identifier (not the typedef) is called the structure's "tag".
Hence, you will see constructs like

typedef struct tagMSG { ... } MSG;
typedef struct point_tag { ... } point_t;

It is not typically useful to specify the tag
except when you need a pointer to the 
struct before it is typedefed, as in a linked list:

typedef struct llist_tag
{
    void*             data;
    struct llist_tag* next;
} llist_t;

llist_t* head = NULL;

http://www.kuqin.com/language/20090406/44443.html

C/C++语法知识:typedef struct 用法详解

第一篇:typedef struct与struct的区别

1. 基本解释
typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。
这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。

在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,
另一个是简化一些比较复杂的类型声明。
至于typedef有什么微妙之处,请你接着看下面对几个问题的具体阐述。

2. typedef & 结构的问题

当用下面的代码定义一个结构时,编译器报了一个错误,为什么呢?
莫非C语言不允许在结构中包含指向它自己的指针吗?请你先猜想一下,然后看下文说明:

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

答案与分析:

1、typedef的最简单使用

typedef long byte_4; // 给已知数据类型long起个新名字,叫byte_4。

2、 typedef与结构结合使用

typedef struct tagMyStruct
{
 int iNum;
 long lLength;
} MyStruct;

这语句实际上完成两个操作:
1) 定义一个新的结构类型

struct tagMyStruct
{
 int iNum;
 long lLength;
};

分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,
struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。
我们可以用struct tagMyStruct varName来定义变量,但要注意,
使用tagMyStruct varName来定义变量是不对的,
因为struct 和tagMyStruct合在一起才能表示一个结构类型。

2) typedef为这个新的结构起了一个名字,叫MyStruct。

typedef struct tagMyStruct MyStruct;

因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。

答案与分析

C语言当然允许在结构中包含指向它自己的指针,我们可以在建立链表等数据结构的实现上看到无数这样的例子,
上述代码的根本问题在于typedef的应用。

根据我们上面的阐述可以知道:新结构建立的过程中遇到了pNext域的声明,类型是pNode,
要知道pNode表示的是类型的新名字,那么在类型本身还没有建立完成的时候,
这个类型的新名字也还不存在,也就是说这个时候编译器根本不认识pNode。

解决这个问题的方法有多种:

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

注意:在这个例子中,你用typedef给一个还未完全声明的类型起新名字。C语言编译器支持这种做法。

struct在代码中常见两种形式:

struct A
{
  //...
};
struct
{
  //...
} A;

这其实是两个完全不同的用法:

前者叫做“结构体类型定义”,意思是:定义{}中的结构为一个名称是“A”的结构体。
这种用法在typedef中一般是:

typedef struct tagA //故意给一个不同的名字,作为结构体的实名
{
  //...
} A; //结构体的别名。

后者是结构体变量定义,意思是:以{}中的结构,定义一个名称为"A"的变量。
这里的结构体称为匿名结构体,是无法被直接引用的。
也可以通过typedef为匿名结构体创建一个别名,从而使得它可以被引用:

typedef struct
{
  //...
} A; //定义匿名结构体的别名为A


第二篇:在 C 和 C++中 struct 和 typedef struct 的区别

在 C 和 C++ 有三种定义结构的方法。

typedef struct  //这种方法可以在c或者c++中定义一个S1结构
{
  int data;
  int text;
} S1;

struct S2 // 这种定义方式只能在C++中使用,而如果用在C中,那么编译器会报错
{
  int data;
  int text;
};

struct { // 这种方法并没有定义一个结构,而是定义了一个s3的结构变量,编译器会为s3内存。
  int data;
  int text;
} S3;

void main()
{
  S1 mine1;// OK ,S1 是一个类型
  S2 mine2;// OK,S2 是一个类型
  S3 mine3;// OK,S3 不是一个类型
  S1.data = 5;// ERRORS1 是一个类型
  S2.data = 5;// ERRORS2 是一个类型
  S3.data = 5;// OKS3是一个变量
}

另外,对与在结构中定义结构本身的变量也有几种写法

struct S6 // 这种写法只能在C++中使用
{
  S6* ptr;
};

typedef struct // 这是一种在C和C++中都是错误的定义
{
  S7* ptr;
} S7;

如果在C中,我们可以使用这样一个“曲线救国的方法“

typedef struct tagS8
{
  tagS8 * ptr;
} S8;

第三篇:struct 和 typedef struct

分三块来讲述:
1 首先:在C中定义一个结构体类型要用typedef:

typedef struct Student
{
  int a;
} Stu;

于是在声明变量的时候就可:Stu stu1;

如果没有typedef就必须用struct Student stu1;来声明

这里的Stu实际上就是struct Student的别名。

另外这里也可以不写Student(于是也不能struct Student stu1;了)

typedef struct
{
  int a;
} Stu;


但在c++里很简单,直接

struct Student
{
  int a;
};

于是就定义了结构体类型Student,声明变量时直接Student stu2;


2其次:在c++中如果用typedef的话,又会造成区别:

struct Student
{
  int a;
} stu1; //stu1是一个变量

使用时可以直接访问stu1.a

typedef struct Student2
{
  int a;
} stu2; //stu2是一个结构体类型

stu2 s2;
s2.a=10;

3 掌握上面两条就可以了,不过最后我们探讨个没多大关系的问题
如果在c程序中我们写:

typedef struct
{
  int num;
  int age;
}aaa,bbb,ccc;


这算什么呢? 我个人观察编译器(VC6)的理解,这相当于

typedef struct
{
  int num;
  int age;
} aaa;

typedef aaa bbb;
typedef aaa ccc;

也就是说aaa,bbb,ccc三者都是结构体类型。
声明变量时用任何一个都可以,在c++中也是如此。
但是你要注意的是这个在c++中如果写掉了typedef关键字,那么aaa,bbb,ccc将是截然不同的三个对象。

第四篇:C/C++中typedef struct和struct的用法

struct _x1
{
  ...
}x1;
typedef struct _x2
{
  ...
} x2;

有什么不同? 其实, 前者是定义了类 _x1 和 _x1 的对象实例 x1,

后者是定义了类 _x2 和 _x2 的类别名 x2
所以它们在使用过程中是有取别的.

[知识点]

结构也是一种数据类型, 可以使用结构变量, 因此, 象其它类型的变量一样, 在使用结构变量时要先对其定义。

定义结构变量的一般格式为:

struct 结构名
{
  类型 变量名;
  类型 变量名;
  ...
} 结构变量;

结构名是结构的标识符不是变量名。

另一种常用格式为:

typedef struct 结构名
{
  类型 变量名;
  类型 变量名;
  ...
} 结构别名;

另外注意: 在C中,struct不能包含函数。
在C++中,对struct进行了扩展,可以包含函数。

#include <iostream>
using namespace std;
typedef struct _point
{
  int x;
  int y;
} point; //定义类,给类一个别名

struct _hello
{
  int x,y;
} hello; //同时定义类和对象

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 pt2;这一行编译将不能通过. 为什么?
  //因为hello是被定义了的对象实例了.
  //正确做法如下: 用hello.x和hello.y

  hello.x = 8;
  hello.y = 10;
  cout<< "hellohello.x=" << hello.x << "hello.y=" <<hello.y <<endl;
  return 0;
}

第五篇:问答

Q:用struct和typedef struct 定义一个结构体有什么区别?为什么会有两种方式呢?

struct Student
{
  int a;
} stu;

typedef struct Student2
{
  int a;
} stu2;

A:事实上,这个东西是从C语言中遗留过来的,typedef可以定义新的复合类型或给现有类型起一个别名,在C语言中,如果你使用

struct xxx { }; 的方法,使用时就必须用 struct xxx var 来声明变量,而使用

typedef struct { }的方法 就可以写为 xxx var;

不过在C++中已经没有这回事了,无论你用哪一种写法都可以使用第二种方式声明变量,这个应该算是C语言的糟粕。


原文地址:https://www.cnblogs.com/shangdawei/p/3017291.html