typedef 中 synonym 的意思是什么?

3
以下段落摘自[dcl.typedef]:
在其声明范围内,typedef 名称在语法上等同于关键字,并以第8条所述的方式命名与标识符相关联的类型。因此,typedef 名称是另一种类型的同义词。typedef 名称不像类声明(9.1)或枚举声明那样引入新类型。
我们需要的另一个相关段落来自[dcl.type]:
通常情况下,在声明的完整声明说明序列中或在类型说明序列或尾随类型说明序列中最多只允许一个类型说明符。唯一的例外是以下情况:……long 可以与 long 结合使用。
在以下代码中,i1 只是 long 的同义词。
typedef long i1;
typedef long i1 i2;

因此,我希望第二行被理解为 typedef long long i2。然而,MSVC2015RC 给出了以下错误信息:

Error C2146 语法错误: 标识符 'i2' 前面缺少';'

有人能指出哪个部分的标准使我的期望无效吗?


更新

我的观点是,就我对 [dcl.type] 简单的语法理解,

type-specifier:
    trailing-type-specifier
    class-specifier
    enum-specifier
trailing-type-specifier:
    simple-type-specifier
    elaborated-type-specifier
    typename-specifier
    cv-qualifier
type-specifier-seq:
    type-specifier attribute-specifier-seq opt
    type-specifier type-specifier-seq
trailing-type-specifier-seq:
    trailing-type-specifier attribute-specifier-seq opt
    trailing-type-specifier trailing-type-specifier-seq

decl-specifier-seq允许一系列类型说明符,只要它们满足组合规则。尽管类型由类型说明符指定,但我认为类型与类型说明符并不相同;-)


2
long long 中,第一个 long 不是第二个 long限定词形容词 - Basile Starynkevitch
1
这里适用的一个规则是[dcl.type] p2 "通常情况下,声明符序列的完整声明符序列或类型说明符序列或尾随类型说明符序列中最多只允许存在一个类型说明符。此规则的唯一例外情况为以下几种:[例外列表]" 另见[dcl.type.simple]p2。 - dyp
@Hector,我不认为这是该部分应该被解释的方式。短语“在语法上等同于关键字”只是意味着typedef名称可以像关键字一样使用。假设i1可以替换long,仅仅因为它们都像关键字一样工作,这有点牵强。 - Apples
1
@hvd 它属于“关键字”语法类别 - 它在语法上不等同于任何特定的关键字,而是等同于所有关键字。 - molbdnilo
2
@Hector i1long int 类型的同义词,而不是关键字 long 的同义词。否则你也可以说 i1 double 并得到一个 long double - Apples
显示剩余6条评论
4个回答

5
好的,我来回答。
首先看一下这个:
typedef-name在语法上等同于关键字
这只是意味着typedef-names遵循关键字的语法。这并不意味着typedef-name等同于任何特定的关键字。它就像一个新的独特的关键字。
然后我们有:
typedef-name因此是另一种类型的同义词。
所以,给定typedef long i1;,这个“另一种类型”是什么?它是long int,而不仅仅是long。
此外,“类型”是什么?至少,类型说明符不是类型。类型说明符long表示类型"long int"(参见n3337的表10或n4296的表9)。
我会把我的评论复制到这里:
i1是long int类型的同义词。它不是关键字long的同义词。否则你也可以说i1 double,并得到一个long double。
虽然也许我应该说,i1不是类型说明符long的同义词,但它是long int类型的同义词。

让我感到困惑的是“typedef名称因此是另一种类型的同义词。” 我将其解读为“typedef名称因此是另一种类型说明符的同义词。” 由于类型说明符可以链接到类型说明符序列中,所以这个问题似乎很自然。 - Hector

3
据我所知,没有语法规则表明一旦T是有效类型,long T就是有效类型。(但对于volatileconst限定符有相关规则)
换句话说,long long应该被视为一个“多单词关键字”(但C和C++标准化委员会非常不愿意引入新的关键字)。
因此,我不认为以下内容是有效的。
 // probably invalid
 typedef int fooT;
 unsigned fooT barv;

我理解你的观点,然而问题是为什么不允许。 - Hector
因为没有规则允许你想要的。 - Basile Starynkevitch
实际上,类型说明符的语法似乎允许这样做。如果类型说明符和类型之间的对应关系是双射的,那么区分这两者就没有意义了。[dcl.type.simple]中的表9显示我们可以从类型说明符映射到类型,但反之则不行。因此,类型说明符的语法并不是类型的语法。 - Hector

1

[dcl.type]第二段规定了longshortsignedunsignedconstvolatile的规则。

通常情况下,在声明的完整类型说明符序列中或类型说明符序列或尾随类型说明符序列中,最多只允许一个类型说明符。以下是唯一的例外:

  • const可以与除自身以外的任何类型说明符组合。

  • volatile可以与除自身以外的任何类型说明符组合。

  • signedunsigned可以与char、long、short或int组合。

  • shortlong可以与int组合。

  • long可以与double组合。

  • long可以与long组合。

因此

typedef long i1;
typedef const i1 i2;

这是有效的,因为const可以与任何类型说明符组合使用。

typedef long i1;
typedef long i1 i2;

由于i1long的名称,但它不是long本身,因此不正确。

在您的示例中,i1在语法上可能等同于关键字,但它不是允许与long组合的限定符之一。它是一个不同的关键字,因此与long的组合规则不适用于它。


0

介绍同义词概念的目的可能有助于理解。 在 C 语言中添加了同义词来解决定义结构时的自引用问题。 例如,当定义用于表示链表元素的结构类型时,您可以按以下方式定义它:

typedef struct {
    int                     some_data; ///< ...or anything
    linked_list_element_t*  previous_element;
    linked_list_element_t*  next_element;
} linked_list_element_t;

问题当然是类型“linked_list_element_t”在typedef结构语句之后才被定义,因此不能在typedef结构语句内部使用。 当然,您可以使用通用的void*指针,但这不是一个好的做法,previous_element和next_element成员可能会被初始化为指向任何东西。
您需要在类型定义中引用该类型。进入同义词:
typedef struct lle_t {
    int     some_data;
    lle_t*  previous_element;
    lle_t*  next_element;
} linked_list_element_t;

在这个简单的例子中,代码将只使用linked_list_element_t来引用该类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接