Con*_*tor 70 c++ gcc g++ c++11
以下代码使用g ++ 4.8.1成功编译:
int main()
{
int(*)();
}
Run Code Online (Sandbox Code Playgroud)
它看起来像一个函数指针的简单声明:
int(*f)();
Run Code Online (Sandbox Code Playgroud)
它不能用clang 3.4和vc ++ 2013编译.
它是编译器错误还是标准的黑暗之处?
int(*)();
int(*);
int(*){};
int(*());
更新1: @Ali在评论中添加了一些有趣的信息:
所有4个案例都使用clang 3.5 trunk(202594)进行编译错误,并使用gcc 4.9 trunk(20140302)进行编译.行为是一样的
-std=c++98 -pedantic,除了int(*){};可以理解的; 扩展初始化程序列表仅适用于-std=c++11.
更新2:正如@CantChooseUsernames在他的回答中指出的那样,即使没有任何启用的优化,即使初始化它们仍然可以正常编译并且没有为它们生成汇编(无论是否初始化):
int(*)() = 0;
int(*) = 0;
int(*){} = 0;
int(*()) = 0;
更新3:我真的很惊讶地发现int(*)() = "Hello, world!";编译也很好(int(*p)() = "Hello, world!";当然不会编译).
更新4:太棒了但int(*){} = Hello, world!;编译得很好.而下面的怪异之极的一段代码,也:int(*){}() = -+*/%&|^~.,:!?$()[]{};(活生生的例子).
这和许多相关的句法问题被跟踪为gcc bug 68265.
Vla*_*cow 15
根据C++标准(第7节声明中的第6页)
6 init-declarator-list 中的每个init-declarator只包含一个declarator-id,它是init-declarator声明的名称,因此声明声明了一个名称
所以它只是一个编译器错误.
有效的代码可能看起来像(除了你显示的函数指针声明),虽然我不能用我的MS VC++ 2010编译它.
int(*p){};
Run Code Online (Sandbox Code Playgroud)
您用于测试的编译器似乎允许声明而没有declarator-id.
还要考虑8.1节类型名称的以下段落
1要显式指定类型转换,并作为sizeof,alignof,new或typeid的参数, 应指定类型的名称.这可以使用type-id来完成,它在语法上是对该类型的变量或函数的声明,省略了实体的名称.
我不确定这有多大帮助,但我尝试了以下(clang 3.3,g ++ 4.8.1):
using P = int(*)();
using Q = int*;
P; // warning only
Q; // warning only
int(*)(); // error (but only in clang)
int*; // error
int(*p)(); // ok
int *q; // ok
Run Code Online (Sandbox Code Playgroud)
另一方面,g ++ 4.8.2和4.9.0中的所有内容都很好.不幸的是,我没有铿锵声3.4.
非常粗略地,声明[iso section 7]按顺序包含以下部分:
static,virtual)const double,vector<int>)n,*p,a[7],f(int))const,noexcept)= {1,2,3}或{ return 0; }现在,说明符大致由名称和任选的一些说明符操作符[异8/4].
前缀运算符,例如:
* (指针)*const (常量指针)& (左值参考)&& (右值参考)auto (函数返回类型,尾随时)后缀运算符,例如:
[] (阵列)() (功能)-> (函数尾随返回类型)上述运算符旨在反映它们在表达式中的用法.Postfix运算符绑定比前缀更紧密,括号可用于更改它们的顺序:int *f()是一个返回指针的函数int,而是int (*f)()一个返回函数的指针int.
也许我错了,但我认为这些运营商不能在声明中没有名字.因此,当我们编写时int *q;,则int是基类型,并且*q是由前缀运算符*后跟名称组成的声明符q.但int *;不能单独出现.
另一方面,当我们定义时using Q = int*;,声明Q;本身就很好,因为Q它是基类型.当然,因为我们没有声明任何内容,我们可能会根据编译器选项获得错误或警告,但这是一个不同的错误.
以上只是我的理解.标准(例如N3337)所说的是[iso 8.3/1]:
每个声明符只包含一个declarator-id ; 它命名声明的标识符.声明器id中出现的unqualified-id应该是一个简单的标识符,除了声明一些特殊函数(12.3 [ 用户定义的转换 ],12.4 [析构函数],13.5 [重载运算符])和模板特化声明或部分专业化(14.7).
(方括号中的注释是我的).所以我理解int(*)();应该是无效的,我不能说为什么它在clang和不同版本的g ++中有不同的行为.
你可以使用这个:http://gcc.godbolt.org/来查看程序集..
int main()
{
int(*)() = 0;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
产生:
main:
pushq %rbp
movq %rsp, %rbp
movl $0, %eax
popq %rbp
ret
Run Code Online (Sandbox Code Playgroud)
这相当于: int main() {return 0;}
所以即使没有优化,gcc也不会为它生成汇编.它应该发出警告或错误吗?我没有任何线索,但它不关心或做任何未命名的func指针.
然而:
int main()
{
int (*p)() = 0;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
没有优化会产生:
main:
pushq %rbp
movq %rsp, %rbp
movq $0, -8(%rbp)
movl $0, %eax
popq %rbp
ret
Run Code Online (Sandbox Code Playgroud)
在堆栈上分配8个字节..