这些语法正确的C++语句有任何意义吗
Do these syntactically correct C++ statements carry any meaning?
当浏览C++语法时,我发现后缀的定义大致如下:
Postfix ::= Primary
| Postfix '[' Expression ']'
| Postfix '(' Expression ')'
| Postfix '.' Identifier
| Postfix '->' Identifier
| Postfix '++'
| Postfix '--'
这意味着foo.f++()
在语法上是有效的——大概是因为函数是指针,它会引用定义的下一个函数,但如果它在语义解析过程中没有被发现是在修改常量对象,我会感到震惊——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 '--'
在解析的语法阶段会出现catch这样的无效表达式。起初,我认为它只是作为遗留的东西留在标准中,但Java和D等较新的语言也做同样的事情,那么这些语句是否具有某种意义,从而导致语法以这种方式定义?
C++实际上并不是由其语法产物定义的。BNF语法是作为语言规则的辅助来帮助理解的,但C++中的语法错误和语义错误 因此,您试图将"语法有效…在语义解析过程中捕获"更改为"在解析的语法阶段捕获此类无效表达式"的改进是完全没有意义的,因为这些实际上并不作为独立阶段存在。 C++编译阶段见本标准 分隔标记的空白字符不再重要。每个预处理令牌都被转换为一个令牌。(2.7)对生成的令牌进行语法和语义分析,并将其翻译为翻译单元。 句法分析和语义分析是密不可分的。语义错误是在解析的句法阶段,即第7阶段捕获的。[lex.phases]
第2.1节。这个主题特别感兴趣的是第7阶段:
另一个有趣的注意事项是,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.
刚刚尝试用gcc
和g++
:编译并运行这个小程序
#include <stdio.h>
void foo() {
printf("foo()n");
}
int main(void) {
void (*bar)() = foo;
bar++();
bar();
}
如果解释为C代码,则没有编译器错误,字符串"foo()\n"会打印两次,但当它试图从foo()
返回时会出现segfault,因为函数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++中没有定义。
- 如何在 if 语句中声明对象并在任何我想的地方使用它?
- 是否可以对任何语句字符串使用预准备语句?
- 我可以使用 try catch 语句来捕获任何错误而不是具体错误吗?
- 在任何案例之前,在 switch 语句中的使用声明是否合法?
- 是否可以编写C++不使用任何条件语句交换输入的函数?
- 这个基于范围的'for'语句需要一个合适的函数,但找不到任何函数
- 当将编译器从G 切换到MSVC时,为什么此开关语句不会返回任何内容
- 这段代码如何在没有任何循环语句或'goto'或递归的情况下循环?
- string.at if 语句不返回任何内容
- Switch语句不显示除默认语句之外的任何类型的输出
- 可以在 main 的返回 0 语句之后调用任何函数吗?
- 我的程序编译并运行,但没有执行 switch 语句中的 6 个选项中的任何一个,我无法弄清楚原因
- 计算没有If/While/For语句或任何数据结构的更改
- 使用gdb似乎表明程序语句没有任何效果
- 如果一个指定返回类型为int的函数没有任何返回语句,即不返回值,它会返回垃圾值吗
- 是否有任何编译器或选项来触发对无意义和有错误的switch语句的警告
- 语句调用构造函数,但对构造函数不做任何操作——为什么它不能编译
- 为什么程序开头的cout语句没有输出任何东西?
- 是否应该依赖if语句捕获除0以外的任何其他整数值为真?
- C++指针赋值语句似乎不起作用/做任何事情