在查看C ++语法时,我发现后缀大致定义如下:
Postfix ::= Primary
| Postfix '[' Expression ']'
| Postfix '(' Expression ')'
| Postfix '.' Identifier
| Postfix '->' Identifier
| Postfix '++'
| Postfix '--'
意味着foo.f++()
在语法上是有效的 - 大概是因为函数是指针,它会引用已定义的下一个函数,但如果它在语义解析期间没有被捕获,我会感到震惊修改一个const对象 - 就像foo.f()<true>;
一样似乎没有任何意义,而foo.++f()
是不允许的,即使它或多或少是相同的作为第一个的东西。此外,定义了一元表达式,以便++*"hello world"
在语法上有效,因为文字被认为与标识符的方式相同。
相反的是:
postfix0 ::= ScopeResolution
| postfix0 '.' postfix2
| postfix0 '->' postfix2
postfix1 ::= postfix0
| postfix1 '<' expression '>'
postfix2 ::= postfix1
| postfix2 '[' expression ']'
| postfix2 '(' expression ']'
postfix3 ::= postfix2
| Literal
| postfix3 '++'
| postfix3 '--'
在解析的句法阶段会出现捕获这样的无效表达式。起初我认为它只是遗留在标准中作为遗留物,但是Java和D等新语言也做同样的事情,因此这些语句带有某种意义导致语法被定义为这种方式?
答案 0 :(得分:10)
C ++实际上并没有通过语法产生来定义。 BNF语法是作为语言规则的伴随提供的,以帮助理解,但语法错误和语义错误之间没有,也不可能有区别。在C ++中,因为它没有无上下文语法。
因此,在将语法分析中“在语法分析期间捕获的语法有效”更改为“在解析的句法阶段捕获此类无效表达式”时,您尝试进行的改进完全没有意义,因为这些实际上并没有作为独立阶段存在。
C ++编译的各个阶段可以在标准的2.1节[lex.phases]
中找到。该主题特别感兴趣的是第7阶段:
分隔标记的空白字符不再重要。每个预处理令牌都转换为令牌。 (2.7)。由此产生的标记在语法和语义上进行分析并翻译为翻译单元。
句法和语义分析是不可分割地一起进行的。语法错误 在解析的句法阶段(第7阶段)被捕获。
答案 1 :(得分:5)
另一个有趣的说明是,foo.f++()
在语义上可以有效。但它与“下一个定义的函数”没有任何关系。
#include <iostream>
struct CallMe {
void operator()() const
{ std::cout << "Used as function call.\n"; }
};
struct F_Type {
CallMe operator++(int)
{ std::cout << "f was incremented.\n"; return {}; }
};
struct Foo_Type {
F_Type f;
} foo;
int main()
{
foo.f++();
}
输出:
f was incremented.
Used as function call.
答案 2 :(得分:2)
尝试使用gcc
和g++
编译并运行这个小程序:
#include <stdio.h>
void foo() {
printf("foo()\n");
}
int main(void) {
void (*bar)() = foo;
bar++();
bar();
}
如果解释为C代码,则没有编译器错误,字符串&#34; foo()\ n&#34;被打印两次,但是当它试图从foo()
返回时会出现段错误,因为部分函数prolog似乎已被跳过。
所以,是的,至少gcc
认为bar++()
是有效的C代码,并且方便地废话。
<强>更新强>
正如zwol指出的那样(感谢),这是由于一个相当危险而非有用的gnu扩展,它处理指向void
的指针,并作为指向大小为1的对象的指针,允许对它们进行指针运算。使用gcc --pedantic -Werror
进行编译会产生预期的错误,gcc -std=c99
没有。
与g++
不同的故事:这里我得到编译器错误
foo.c: In function ‘int main()’:
foo.c:9:5: error: ISO C++ forbids incrementing a pointer of type ‘void (*)()’ [-fpermissive]
这是C ++标准中的一项规定(第5.2.6节,正如Ben Voigt所指出的,谢谢):函数指针的指针算法未在C ++中定义。