2012-04-10 67 views
5

Tôi đã gặp một số vấn đề với mã mẫu tôi đã thử nghiệm, vì hàm abs của tôi không trả lại kết quả chính xác. abs (-2) được outputing -2 (điều này, bằng cách này, là nghĩa vụ phải được hàm giá trị tuyệt đối, nếu đó là không rõ ràng)GCC tên hàm xung đột

Sau khi nhận được một chút tuyệt vọng, tôi cuối cùng đã có đoạn mã sau

#include <stdio.h> 

unsigned int abs(int x) { 
    return 1; 
} 

int main() { 
    printf("%d\n", abs(-2)); 
    return 0; 
} 

Điều này không có gì hữu ích nhưng nó phục vụ để hiển thị vấn đề của tôi. Đây là kết quả đầu ra -2, khi nó được mong đợi xuất ra 1.

nếu tôi thay đổi tên chức năng thành tên khác (ví dụ abs2), kết quả bây giờ là chính xác. Ngoài ra, nếu tôi thay đổi nó để nhận được hai đối số thay vì một, nó cũng sửa chữa vấn đề.

Đoán hiển nhiên của tôi: xung đột với chức năng abs standart. Nhưng điều này vẫn không giải thích tại sao đầu ra là -2 (nó phải là 2, nếu sử dụng chức năng abs standart). Tôi đã thử kiểm tra sản lượng lắp ráp của cả hai phiên bản (với các hàm có tên abs và abs2)

Dưới đây là đầu ra khác cho cả assemblys:

23,25c23,25 
< .globl abs 
< .type abs, @function 
< abs: 
--- 
> .globl abs2 
> .type abs2, @function 
> abs2: 
54c54 
< .size abs, .-abs 
--- 
> .size abs2, .-abs2 
71c71,74 
< movl -4(%rbp), %edx 
--- 
> movl -4(%rbp), %eax 
> movl %eax, %edi 
> call abs2 
> movl %eax, %edx 

Từ những gì tôi hiểu, phiên bản đầu tiên (trong đó chức năng là tên là abs) chỉ đơn giản là loại bỏ các cuộc gọi chức năng, do đó bằng cách sử dụng tham số x thay vì abs (x)

Vì vậy, để tổng kết: tại sao điều này xảy ra, đặc biệt là vì tôi không thể tìm thấy một cách để có được bất kỳ loại cảnh báo hoặc lỗi về điều này.

Thử nghiệm trên Bóp Debian, GGC 4.4.5, và cũng trên gcc 4.1.2

+0

đây là một ví dụ trong ideone http://ideone.com/YpnkE –

Trả lời

7

GCC đang chơi thủ đoạn trên bạn do sự tương tác giữa các nội dung sau:

  • abs là một built- trong chức năng;
  • bạn đang khai báo abs để trả lại unsigned int trong khi chuẩn (và được tích hợp sẵn) abs trả lại signed int.

Thử biên dịch với gcc -fno-builtin; trên hộp của tôi, cho kết quả mong đợi là 1. Biên dịch không có tùy chọn đó nhưng với abs được khai báo là trả lại signed int làm cho chương trình in 2.

(Các giải pháp thực tế cho vấn đề này là không sử dụng định danh thư viện cho các chức năng của riêng bạn. Cũng lưu ý rằng bạn không nên in một unsigned int với %d.)

+0

Cảm ơn, làm rõ một phần của nó. tôi biết về các chức năng dựng sẵn, và tôi mặc dù một cái gì đó như -fno-builtin có thể sẽ giải quyết nó, nhưng tôi không biết tên cờ thực sự. Tuy nhiên, khi sử dụng giải pháp thứ hai của bạn (khai báo hàm như int đã ký) đầu ra của 2 ngụ ý rằng hàm dựng sẵn đang được gọi thay vì của tôi, dẫn đến câu hỏi khác của tôi: tôi không nên nhận cảnh báo về hành vi này? Trong một dự án quy mô lớn, thực tế, loại vấn đề này có thể là một cơn đau đầu thực sự để xác định – Naps62

+0

@ Naps62: vâng, một cảnh báo sẽ tốt đẹp, nhưng có vẻ như GCC (thậm chí là '-Wall -Wextra -pedantic') sẽ không cung cấp cho bạn một. Tốt hơn hãy cẩn thận với số nhận dạng của bạn. –

2

gcc tối ưu hóa các cuộc gọi đến abs() sử dụng của nó được xây dựng trong abs(). Vì vậy, nếu bạn sử dụng tùy chọn -fno-builtin (hoặc xác định abs() của bạn là trở về int), bạn sẽ nhận thấy bạn nhận được kết quả chính xác. Theo this (trích dẫn):

GCC bao gồm tích hợp trong các phiên bản của nhiều chức năng trong thư viện C chuẩn .Các phiên bản có tiền tố _ được dựng sẵn sẽ luôn là được coi là có cùng ý nghĩa với chức năng thư viện C ngay cả nếu bạn chỉ định tùy chọn -fno-builtin. (xem C Tùy chọn phương ngữ) Nhiều của các chức năng này chỉ được tối ưu hóa trong một số trường hợp nhất định; nếu chúng là không được tối ưu hóa trong một trường hợp cụ thể, một cuộc gọi đến chức năng thư viện sẽ được phát ra.

Bạn đã bao gồm stdlib.h, trong đó tuyên bố abs() ngay từ đầu, bạn sẽ gặp lỗi khi biên dịch.

+0

Chương trình tôi đăng không rơi trở lại chức năng dựng sẵn như mong đợi. thay vào đó nó chỉ đơn giản là bỏ qua cuộc gọi hàm, xử lý abs (-2) là -2. Ngoài ra, tôi đã cố gắng đề xuất của bạn để bao gồm stdlib.h, và không có lỗi biên dịch thời gian, vấn đề vẫn còn – Naps62

+0

Tôi thấy rằng khó tin, vì bạn đang xác định một hàm gọi là 'abs() 'với các loại xung đột với một trong 'stdlib.h'. Ngay cả khi không có bất kỳ tùy chọn nghiêm ngặt hoặc pedantic nào, gcc 4.1.2 và 4.4.7 đều phát ra các lỗi biên dịch. –

2

Nghe có vẻ giống như this bug, bắt đầu từ năm 2007 và được ghi chú là cố định.

Tất nhiên, bạn nên cố gắng biên dịch mà không có nội dung của GCC, tức là vượt qua -fno-builtin (hoặc chỉ -fno-builtin-abs để bắn tỉa chỉ abs()) khi biên dịch.

Các vấn đề liên quan