C语言中的变量的带括号的标识符

huangapple go评论65阅读模式
英文:

Parenthesized identifier of a variable in C

问题

I am interested in how the compiler parses certain declarations and why does it allow them in the first place.

Consider the following shred of code: int(var);

which most likely nobody would ever write, but it appears to be allowed by GCC C99 for some reason (a language extension?).
To me, knowing exactly how the declarations are parsed, this makes sense albeit useless and an obvious bad practice in the slightest.

The problem is that this introduces a new difficulty in parsing declarations as such:

int func ( int(var), int(void) );

Here, since identifiers in argument declarations are optional, the compiler must do what exactly? Attempt to retrieve 'void' as an identifier, but instead of producing an error as usual, allow it since it matches the syntax of a function (void) returning int?
This presents a challenge when you would want to parse such a declaration and I want to make sure I am doing it correctly.

It starts to make less sense and become more confusing with declarations like this one:

void c (int())

Because the argument will be treated as a function returning int instead of

void c (int);

Please, shed some light on the subject.

英文:

I am interested in how the compiler parses certain declarations and why does it allow them in the first place.

Consider the following shred of code: int(var);

which most likely nobody would ever write, but it appears to be allowed by GCC C99 for some reason (a language extension?).
To me, knowing exactly how the declarations are parsed, this makes sense albeit useless and an obvious bad practice in the slightest.

The problem is that this introduces a new difficulty in parsing declarations as such:

int func ( int(var), int(void) );

Here, since identifiers in argument declarations are optional, the compiler must do what exactly? Attempt to retrieve 'void' as an identifier, but instead of producing an error as usual, allow it since it matches the syntax of a function (void) returning int?
This presents a challenge when you would want to parse such a declaration and I want to make sure I am doing it correctly.

It starts to make less sense and become more confusing with declarations like this one:

void c (int())

Because the argument will be treated as a function returning int instead of

void c (int);

Please, shed some light on the subject.

答案1

得分: 2

根据C语法(6.7.6 声明符)

语法
    1 声明符:
        指针可选 直接声明符
    直接声明符:
        标识符
        ( 声明符 )
    //...

声明符可以用括号括起来。

例如,这个数组声明

int a[M][N];

可以重写为

int ( ( ( a )[M] )[N] );

至于这个函数声明

int func ( int(var), int(void) );

那么声明了两个参数:一个名为parameter,类型为int,另一个未命名参数的函数类型为int ( void )

在C语言中,在函数声明中,如果不同时进行定义,您可以省略参数的标识符。

至于这个声明

void c (int());

那么参数再次具有函数类型。

英文:

According to the C grammar (6.7.6 Declarators)

Syntax
    1 declarator:
        pointeropt direct-declarator
    direct-declarator:
        identifier
        ( declarator )
    //...

declarators may be enclosed in parentheses.

For example this array declaration

int a[M][N];

may be rewritten like

int ( ( ( a )[M] )[N] );

As for this function declaration

int func ( int(var), int(void) );

then there are declared two parameters: one named parameter of the type int and other unnamed parameter of the function type int ( void ).

In C in function declarations that are not at the same time their definitions you may omit identifiers of parameters.

As for this declaration

void c (int());

then again the parameter has a function type.

答案2

得分: 1

圆括号在声明中是允许的,因为它们需要用来创建某些复合类型,比如:

int *x[3];    // 一个包含3个指向`int`的指针的数组。
int (*x)[3];  // 一个指向包含3个`int`的数组的指针。

使用 int (x) 只是以一种不必要的方式使用了允许的语法。

当你想要解析这样的声明时,这会带来一些挑战,我想确保我正在正确地做这件事。

通常,C语法不是通过研究语法规则并手动编写代码来解析的。解析理论通常在大学计算机科学课程中教授,它研究编程语言的形式描述以及形式语言语法的数学转换,将其转化为解析语法的软件。有软件工具可以执行这种转换。

Yacc 就是这样一种工具,通常与 Lex 配对使用进行词法分析。使用Yacc,你可以编写语法规则,就像它们在C标准中出现的方式一样,并伴随着用于处理解析标记的源代码,Yacc工具会将规则转换为解析源代码。

脚注

1 在简单声明中使用圆括号并不完全没有用处。一个用途是在写北半球春季某个日期的Stack Overflow问题时。

英文:

Parentheses are allowed in declarations because they are needed to create certain compound types, such as:

int *x[3];    // An array of 3 pointers to `int`.
int (*x)[3];  // A pointer to an array of 3 `int`.

Using int (x) is merely using the allowed grammar in a way that is needless.<sup>1</sup>

> This presents a challenge when you would want to parse such a declaration and I want to make sure I am doing it correctly.

The C grammar is generally not parsed by studying the grammar rules and manually writing code for it. Parsing theory, generally taught in university computer science curricula, studies formal descriptions of programming languages and mathematical transformations of a formal language grammar into software that parses the grammar. There are software tools to perform this transformation.

Yacc is one such tool, often paired with Lex to do lexical analysis. With Yacc, you would write grammar rules, much as they appear in the C standard, and accompany them with source code to process the parsed tokens, and the Yacc tool would transform the rules into parsing source code.

Footnote

<sup>1</sup> Parenthesizing identifiers in simple declarators is not entirely useless. One use is in writing Stack Overflow questions for a certain date in the spring of the northern hemisphere.

huangapple
  • 本文由 发表于 2023年6月8日 02:15:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76426041.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定