¿Por qué la declaración "2i;" ¿NO causa un error del compilador?

82

En lugar de 2*i, escribí descuidadamente 2i:

int foo(int i)
{
    2i;
    return 2i;
}

Esperaba que el compilador detectara el error. Pero no lo hizo. Entonces, ¿es 2iuna declaración válida en C? Si es así, ¿qué hace? ¡Perplejo!

Compilé usando gcc versión 5.3.0 y aquí está el resultado del ensamblaje:

    .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
daltonfury42
fuente
¿Qué compilador es ese?
Iharob Al Asimi
No trabajo con _Complexnúmeros. Después de leer un poco el estándar y el enlace proporcionado, creo que la respuesta de @ iharob es correcta.
demasiado honesto para este sitio
@Olaf La rápida transformada de Fourier en el oeste fftw usa el _Complextipo. Descubrí esto mientras escribía un software de procesamiento de datos para mi tesis ( Física en realidad, no informática ni nada parecido ) ( tuve que aplicar un filtro de paso bajo, por lo que la convolución es la Transformada rápida de Fourier, así que sigues adelante ).
Iharob Al Asimi
@iharob: Hmm, ¿eso es más rápido que el ffte y si no, puedo usar el más rápido si vivo en el oeste, pero al este de ti? ;-) En serio: gracias por la información. Como parece, el estándar C ni siquiera admite una notación simple similar con C11.
demasiado honesto para este sitio
¡Un muy buen ejemplo de "... no 'Eureka' sino 'Eso es gracioso ...'"!
Jongware

Respuestas:

107

Esta es una extensión gcc y 2ies la constante imaginaria ingrese la descripción de la imagen aquí. Entonces puedes escribir un número complejo así:

#include <complex.h>

_Complex x = 4 + 5i;
Iharob Al Asimi
fuente
12
¡Vaya, eso fue una sorpresa! ¿Me dirás por qué funcionó incluso cuando no incluí el archivo de encabezado complex.h?
daltonfury42
4
@ daltonfury42 El encabezado es para el _Complextipo, 2ies una constante ( como lo entiende gcc ). Agregue la bandera std=c99o std=c11combinada con -Wally verá una advertencia. Además, de hecho no devuelve, 0pero dado que el tipo de retorno debe ser _Complexy el valor 0 + 2i, no puede inspeccionarlo con printf(). ¡Quizás esa sea solo la parte real0 !
Iharob Al Asimi
12
@ daltonfury42: tampoco es necesario #include <float.h>(o math.h) obtener soporte para constantes de punto flotante .
demasiado honesto para este sitio
2
@ daltonfury42 Eso es correcto. Los archivos de cabecera no cambian la sintaxis del lenguaje, que acaba de declarar cosas como variables, funciones, tipos, etc.
Barmar
2
@ daltonfury42 Aunque podría haber sido posible que el reconocimiento de esta sintaxis fuera controlado por a #pragma, lo que complex.hpodría generar un problema. Pero no lo hicieron de esta manera.
Barmar
13

2ies una gccextensión de un literal entero complejo, un número imaginario puro dos veces la raíz cuadrada de -1. Esta extensión también es compatible con clang.

Es algo sorprendente que su compilación gcc 5.4.0produzca el resultado del ensamblado publicado:

  • Compilando en http://gcc.godbolt.org/# Recibo un error de compilación de gcc5.3.0 http://gcc.godbolt.org/#:: error: cannot convert '__complex__ int' to 'int' in return.
  • El código de ensamblaje publicado para la función fooes incorrecto: no regresa 0. La conversión de la constante entera compleja 2ien intdebería devolver su parte real 0.

Por el contrario, con clang3.7, se compila sin una advertencia y genera un código óptimo, pero por supuesto no es lo que esperas:

foo(int):                       # @foo(int)
    xorl    %eax, %eax
    retq

Esta sintaxis se puede combinar con otros sufijos en cualquier orden. Compilar el código a continuación con clang -Weverythingme da las advertencias adecuadas 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;
}

Produce esta salida en mi entorno:

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

Prueba el último con tu editor de colores de sintaxis ;-)

chqrlie
fuente
Bueno, esto es lo que obtuve cuando usé GCC 5.3.0 en mi PC con Arch Linux. Aquí está mi configuración de gcc si está interesado.
daltonfury42