Tại sao câu lệnh "2i;" KHÔNG gây ra lỗi trình biên dịch?


82

Thay vào đó 2*i, tôi đã bất cẩn viết 2i:

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

Tôi mong đợi trình biên dịch để bắt lỗi. Nhưng nó không. Vì vậy, 2imột câu lệnh hợp lệ trong C? Nếu vậy nó làm gì? Khó hiểu!

Tôi đã biên dịch bằng cách sử dụng gcc phiên bản 5.3.0 và đây là kết quả lắp ráp:

    .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

Đó là trình biên dịch nào?
Iharob Al Asimi

Tôi không làm việc với những _Complexcon số. Sau khi đọc một số tiêu chuẩn và liên kết được cung cấp, tôi nghĩ câu trả lời của @ iharob là đúng.
quá trung thực cho trang web này

@Olaf Biến đổi Fourier fastet ở phương Tây fftw sử dụng _Complexloại. Tôi phát hiện ra điều này khi đang viết phần mềm xử lý dữ liệu cho luận án của mình ( Thực ra là Vật lý, không phải khoa học máy tính hay tương tự ) - ( Tôi phải áp dụng bộ lọc thông thấp, vì vậy tích chập nên Fast Fourier Transform, fftw ).
Iharob Al Asimi

@iharob: Hmm, có nhanh hơn ffte không và nếu không, tôi có được phép sử dụng tốc độ nhanh hơn nếu tôi sống ở phía tây, nhưng phía đông của bạn? ;-) Nghiêm túc: cảm ơn vì thông tin. Có vẻ như, tiêu chuẩn C thậm chí không hỗ trợ ký hiệu đơn giản tương tự với C11.
quá trung thực cho trang web này

Một ví dụ rất hay về ".. không phải 'Eureka' mà là 'Thật buồn cười ...'"!
Jongware

Câu trả lời:


107

Đây là phần mở rộng gcc2ilà hằng số tưởng tượng nhập mô tả hình ảnh ở đây. Vì vậy, bạn có thể viết một số phức như vậy:

#include <complex.h>

_Complex x = 4 + 5i;

12
Wow, điều đó thật bất ngờ! Bạn sẽ cho tôi biết tại sao nó hoạt động ngay cả khi tôi không bao gồm tệp tiêu đề complex.h?
daltonfury42

4
@ daltonfury42 Tiêu đề dành cho _Complexkiểu, 2ilà một hằng số ( theo cách hiểu của gcc ). Thêm std=c99hoặc std=c11kết hợp cờ -Wallvà bạn sẽ thấy một cảnh báo. Ngoài ra, thực sự nó không trả về 0nhưng vì kiểu trả về phải là _Complexvà giá trị 0 + 2i, bạn không thể kiểm tra nó bằng printf(). Vì vậy, có lẽ đó chỉ là phần thực0 !
Iharob Al Asimi

12
@ daltonfury42: Bạn cũng không cần phải #include <float.h>(hoặc math.h) nhận hỗ trợ cho hằng số dấu phẩy động .
quá trung thực cho trang web này

2
@ daltonfury42 Đúng vậy. Tập tin tiêu đề không thay đổi cú pháp ngôn ngữ, họ chỉ cần khai báo những thứ như các biến, chức năng, các loại vv
Barmar

2
@ daltonfury42 Mặc dù có thể có khả năng nhận dạng cú pháp này được kiểm soát bởi a #pragma, complex.hcó thể gây ra vấn đề. Nhưng họ đã không làm theo cách này.
Barmar

13

2igccphần mở rộng cho một chữ số nguyên phức, một số thuần ảo gấp đôi căn bậc hai của -1. Phần mở rộng này cũng được hỗ trợ bởi clang.

Điều hơi ngạc nhiên là quá trình biên dịch của bạn với gcc 5.4.0tạo ra kết quả lắp ráp đã đăng:

  • Biên dịch trên http://gcc.godbolt.org/# Tôi gặp lỗi biên dịch từ gcc5.3.0 http://gcc.godbolt.org/#:: error: cannot convert '__complex__ int' to 'int' in return.
  • Mã lắp ráp đã đăng cho chức năng fookhông chính xác: nó không trả về 0. Chuyển đổi hằng số nguyên phức 2ithành intsẽ trả về phần thực của nó 0.

Ngược lại, với clang3.7, nó biên dịch mà không có cảnh báo và tạo ra mã tối ưu, nhưng tất nhiên không phải những gì bạn mong đợi:

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

Cú pháp này có thể được kết hợp với các hậu tố khác theo bất kỳ thứ tự nào. Việc biên dịch mã bên dưới với clang -Weverythingcác cảnh báo thích hợp cho tôi 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;
}

Nó tạo ra đầu ra này trong môi trường của tôi:

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

Hãy thử cái cuối cùng với trình chỉnh sửa màu cú pháp của bạn ;-)


Đây là những gì tôi nhận được khi sử dụng GCC 5.3.0 trên PC chạy Arch Linux. Đây là cấu hình gcc của tôi nếu bạn quan tâm.
daltonfury42
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.