为啥声明“2i;”不会导致编译器错误?
Posted
技术标签:
【中文标题】为啥声明“2i;”不会导致编译器错误?【英文标题】:Why does the statement "2i;" NOT cause a compiler error?为什么声明“2i;”不会导致编译器错误? 【发布时间】:2016-05-13 01:03:10 【问题描述】:我不小心写了2*i
,而不是2i
:
int foo(int i)
2i;
return 2i;
我希望编译器能够捕捉到错误。但它没有。那么2i
是 C 语言中的有效语句吗?如果是这样,它有什么作用?困惑!
我使用 gcc 版本 5.3.0 编译,这是汇编输出:
.file "strange.c"
.text
.globl foo
.type foo, @function
foo:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
nop
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size foo, .-foo
.ident "GCC: (GNU) 5.3.0"
.section .note.GNU-stack,"",@progbits
【问题讨论】:
那是什么编译器? 我不使用_Complex
号码。在阅读了一些标准和提供的链接之后,我认为@iharob 的回答是正确的。
@Olaf 西方的fastet傅里叶变换fftw使用_Complex
类型。我在为我的论文编写数据处理软件时发现了这一点(实际上是物理学,而不是计算机科学或类似的科学)-(我必须应用低通滤波器,所以卷积所以快速傅里叶变换,所以fftw)。
@iharob:嗯,这比 ffte 快吗?如果不是,如果我住在西部,但在你的东部,我可以使用更快的吗? ;-) 说真的:感谢您提供的信息。看起来,C 标准甚至不支持与 C11 类似的简单表示法。
一个很好的例子“......不是'Eureka'而是'这很有趣......'”!
【参考方案1】:
这是一个gcc extension,而2i
是虚常数。所以你可以像这样写一个复数:
#include <complex.h>
_Complex x = 4 + 5i;
【讨论】:
哇,真是个惊喜!你能告诉我为什么即使我没有包含 complex.h 头文件它也能工作吗? @daltonfury42 标头用于_Complex
类型,2i
是一个常量(gcc 理解它)。添加std=c99
或std=c11
标志并结合-Wall
,您将看到警告。此外,它确实不返回0
,但由于返回类型应该是_Complex
和值0 + 2i
,你不能用printf()
检查它。所以也许这只是真正的部分0
!
@daltonfury42:您也不必通过#include <float.h>
(或math.h
)获得对浮点常量的支持。
@daltonfury42 没错。头文件不会改变语言语法,它们只是声明变量、函数、类型等。
@daltonfury42 尽管有可能通过#pragma
控制对这种语法的识别,complex.h
可能会发出此问题。但他们没有这样做。【参考方案2】:
2i
是复数整数文字的gcc
扩展,是-1
平方根的两倍的纯虚数。 clang
也支持此扩展。
使用gcc 5.4.0
进行编译会产生发布的程序集输出,这有点令人惊讶:
gcc
5.3.0 的编译错误:http://gcc.godbolt.org/#
:error: cannot convert '__complex__ int' to 'int' in return
。
发布的函数foo
的汇编代码不正确:它不返回0
。将复整数常量 2i
转换为 int
应该返回其实部 0
。
相反,使用clang
3.7,它会在没有警告的情况下编译并生成最佳代码,但当然不是您所期望的:
foo(int): # @foo(int)
xorl %eax, %eax
retq
此语法可以以任何顺序与其他后缀组合。用clang -Weverything
编译下面的代码会给我适当的警告warning: imaginary constants are a GNU extension [-Wgnu-imaginary-constant]
:
#include <stdio.h>
int main()
/* complex integer literals */
printf("sizeof(2i) = %zd\n", sizeof(2i));
printf("sizeof(2ui) = %zd\n", sizeof(2ui));
printf("sizeof(2li) = %zd\n", sizeof(2li));
printf("sizeof(2lli) = %zd\n", sizeof(2lli));
/* complex floating point literals */
printf("sizeof(2.i) = %zd\n", sizeof(2.i));
printf("sizeof(2.fi) = %zd\n", sizeof(2.fi));
printf("sizeof(2e0fi) = %zd\n", sizeof(2e0fi));
printf("sizeof(2e0i) = %zd\n", sizeof(2e0i));
/* alternate order */
printf("sizeof(2il) = %zd\n", sizeof(2il));
printf("sizeof(2ill) = %zd\n", sizeof(2ill));
printf("sizeof(2.if) = %zd\n", sizeof(2.if));
return 0;
它在我的环境中产生这个输出:
sizeof(2i) = 8
sizeof(2ui) = 8
sizeof(2li) = 16
sizeof(2lli) = 16
sizeof(2.i) = 16
sizeof(2.fi) = 8
sizeof(2e0fi) = 8
sizeof(2e0i) = 16
sizeof(2il) = 16
sizeof(2ill) = 16
sizeof(2.if) = 8
用你的语法着色编辑器试试最后一个;-)
【讨论】:
嗯,这就是我在运行 Arch Linux 的 PC 上使用 GCC 5.3.0 时得到的结果。 Here 是我的 gcc 配置,如果你有兴趣的话。以上是关于为啥声明“2i;”不会导致编译器错误?的主要内容,如果未能解决你的问题,请参考以下文章
在我将编译器设置设置为支持 c++11 后,我仍然收到错误“stoi”未声明。为啥? [复制]
为啥将 lambda 传递给受约束的类型模板参数会导致“不完整类型”编译器错误?
为啥在 MFC 应用程序中设置 DEBUG_NEW 会导致编译器错误