2013-04-11 30 views
5

Tôi có mã được biên dịch một cách vui vẻ với phiên bản g ++ 3.something. Sau đó tôi muốn xây dựng một số mã khác có biểu tượng C++ 11 trong đó vì vậy tôi đã nâng cấp lên g ++ 4.7. Bây giờ mã ban đầu của tôi không xây dựng. Tôi nhận được lỗi:Lỗi "'fdopen' không được khai báo" được tìm thấy với g ++ 4 được biên soạn với g ++ 3

'fdopen' đã không được khai báo trong phạm vi này

Theo trang man, fdopen() được khai báo trong stdio.h mà tôi đang kể. Tôi không chắc nó có liên quan, nhưng tôi đang làm việc trong môi trường Cygwin. Phiên bản chính xác của g ++ tôi đang sử dụng là phiên bản 4.7.2 do Cygwin cung cấp.

Tôi chưa thay đổi mã này kể từ khi tôi chuyển trình biên dịch và tôi chắc chắn có thể xác nhận rằng nó được xây dựng và mã thử nghiệm của tôi chạy và được chuyển với trình biên dịch trước đó.

Theo yêu cầu, mã ví dụ để chứng minh vấn đề:

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

int main(int argc, char **argv) 
{ 
    int fd; 
    FILE *fp; 

    fd = open("test.txt", (O_WRONLY | O_CREAT | O_EXCL), S_IRWXU); 
    if(0 < fd) 
    { 
     fp = fdopen(fd, "wb"); 

     fprintf(fp, "Testing...\n"); 
     fclose(fp); 
    } 

    return 0; 
} 


# g++ -std=c++11 -o test test.cpp 
test.cpp: In function 'int main(int, char**)': 
test.cpp:14:29: error: 'fdopen' was not declared in this scope 
+0

Nếu không nhìn thấy một số mã, thật khó để biết chắc chắn, nếu bạn có thể ngưng tụ nó xuống một mẫu nhỏ vẫn cho thấy sự cố có thể hữu ích. –

+0

Đã thêm mã. Tôi đã viết nó từ đầu. Lời xin lỗi của tôi, tôi nghĩ rằng từ mô tả vấn đề, mã trên có thể được giả định, nếu cần thiết. Về cơ bản fdopen được khai báo trong theo trang người đàn ông và biên dịch với g ++ 3 chức năng được tìm thấy và với g ++ 4 nó không phải là. Vì vậy, chỉ cần đặt fdopen() trong một số mã và biên dịch để có được cùng một vấn đề. – AlastairG

Trả lời

3

vấn đề này xuất phát từ -std=c++11. Hàm fdopen() không có trong ANSI C (chỉ trong tiêu chuẩn POSIX) và biên dịch với tùy chọn -std=c++11 ngụ ý xác định __STRICT_ANSI__, loại trừ một số chức năng từ stdio.h. Nhân tiện, trong các chương trình C++, bạn thường nên bao gồm <cstdio> thay vì <stdio.h>, xem tại đây: stdio.h not standard in C++?.

Nếu bạn cần sử dụng fdopen(), bạn có thể muốn xóa tùy chọn -std=c++11 khi biên dịch. Một soltion càng tốt, mặc dù không thực sự thanh lịch, có thể sử dụng điều này trong mã nguồn của bạn:

#ifdef __STRICT_ANSI__ 
#undef __STRICT_ANSI__ 
#include <cstdio> 
#define __STRICT_ANSI__ 
#else 
#include <cstdio> 
#endif 

(mà được thiết kế để làm việc với và không có tùy chọn -std=c++11).

+0

Không tốt. Tôi cần cờ C++ 11 vì ai đó đang làm việc trên dự án đang sử dụng kiểu C++ 11. Tôi cần fdopen vì tôi cần phải mở tập tin với cờ và sau đó chuyển đổi nó thành một con trỏ tập tin. Bạn không thể mở tệp dưới dạng tạo độc quyền bằng fopen(). Có vẻ như tôi bị say. – AlastairG

+0

Bạn có thể thử với điều này: '#undef __STRICT_ANSI__' ' #include ' ' #define __STRICT_ANSI__' Nó không phải là rất tao nhã, nhưng hoạt động ... sẽ bổ sung thêm rằng câu trả lời quá, trong trường hợp nó có thể giúp ai đó. – Ale

8

Bất kể bạn làm gì, xin đừng gây rối với cờ __STRICT_ANSI__. Biểu tượng đó được kiểm soát bởi GCC. Bạn nên để GCC xác định nó và để nó một mình.

Điều bạn đang thực sự tìm kiếm là macro thử nghiệm tính năng _POSIX_C_SOURCE. Bạn thấy, fdopen không được xác định theo tiêu chuẩn ngôn ngữ C. Khi bạn nói với GCC rằng bạn đang viết một chương trình C++ 11, thì GCC chuyển sang chế độ "nghiêm ngặt", nơi nó cố gắng không định nghĩa bất kỳ hàm nào không được định nghĩa bởi ngôn ngữ. Điều này là để tránh va chạm tên với mã của riêng bạn. Ví dụ, một chương trình C++ 11 hợp lệ là miễn phí để xác định hàm riêng của nó có tên là fdopenfdopen không phải là một định danh được đặt trước trong ngôn ngữ.

Nhưng fdopen được định nghĩa bởi POSIX, là tiêu chuẩn bao gồm, nhưng tách biệt với tiêu chuẩn ngôn ngữ C. Khi viết một ứng dụng sử dụng các chức năng POSIX, như fdopen, , bạn phải thông báo cho hệ thống rằng bạn có ý định viết một ứng dụng POSIX để nó biết rằng nó sẽ làm cho các chức năng được xác định bởi POSIX có sẵn cho chương trình của bạn. Đây là nơi mà macro kiểm tra tính năng _POSIX_C_SOURCE xuất hiện. Ở đầu mỗi tệp nguồn, trước khi đưa vào bất kỳ tiêu đề nào, hãy xác định macro này với giá trị thích hợp. Ví dụ:

#define _POSIX_C_SOURCE 200112L 

Giá trị bạn nên sử dụng trong định nghĩa tùy thuộc vào phiên bản POSIX bạn đang nhắm mục tiêu. Nếu bạn không chắc chắn về phiên bản nào bạn muốn nhắm mục tiêu, bạn có thể chỉ nhắm mục tiêu cùng một phiên bản mà hệ thống lưu trữ của bạn tuân thủ.Bạn có thể xác định điều này bằng cách chạy getconf từ một vỏ:

$ getconf _POSIX_VERSION 
200809L 
$ _ 

Ở đây, hệ thống của tôi nói với tôi đó là phù hợp với POSIX phiên bản 200809L (ví dụ: POSIX.1-2008). Tôi có thể #define _POSIX_C_SOURCE 200809L trong mã nguồn của mình và tự tin rằng tất cả các tính năng tiêu chuẩn được hệ thống của tôi hỗ trợ sẽ được cung cấp cho tôi.

+0

Không hoạt động với phiên bản gcc MinGW 4.7.0 trên Windows. – Ale

+1

@Ale: Đó là vì các nhà phát triển Newlib (người viết thư viện C được Cygwin và MinGW sử dụng) cũng không hiểu mục đích của các macro thử nghiệm tính năng POSIX. Điều này đã được một vấn đề với Newlib trong nhiều năm, mặc dù nó đã được chỉ ra cho họ nhiều lần (cho một ví dụ thú vị, xem http://cygwin.com/ml/cygwin/2011-10/msg00145.html; toàn bộ thread là tuyệt vời!) Họ chỉ bây giờ nhận được xung quanh để dần dần sửa chữa các tập tin tiêu đề của họ. Thật không may, họ vẫn chưa sửa '' trong đó 'fdopen' được khai báo. –

+2

@Ale: Correction: MinGW không sử dụng Newlib. Nhưng các tập tin tiêu đề của họ có cùng một sai lầm (có thể là do tổ tiên chung của họ với Cygwin; hoặc có thể nó chỉ là * phổ biến cho các lập trình viên không hiểu các macro thử nghiệm tính năng POSIX). Trong mọi trường hợp, MinGW là một ví dụ tồi vì các nhà phát triển MinGW tuyên bố họ không phát triển một hệ thống tuân thủ POSIX. Việc kiểm tra các tính năng POSIX (như 'fdopen') trên hệ thống không phải là vô nghĩa và không muốn, tuân thủ POSIX. –

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