¿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

¿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;

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 ;-)


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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.