2010-10-03 40 views
6

Trong C, không phải là lỗi khi truyền con trỏ đến và đi từ void *.Relax void * casting in C++

Một trở ngại lớn trong việc chuyển sang C++ là cần phải đưa con trỏ khi trở về từ các hàm xử lý các con trỏ chung như malloc và các hàm được khai báo trong mã của riêng tôi chẳng hạn như void *block_get(Blkno const blkno);.

Mã của tôi tuy nhiên được dự định sẽ được biên soạn bằng C trình biên dịch C++ thành công. Nếu tôi cung cấp rõ ràng phôi ở khắp mọi nơi vì lợi ích của C + +, họ phải là C-phong cách phôi và tôi có thể được che lỗi do đúc non-pointer loại đến và từ các loại con trỏ từ cả hai ngôn ngữ.

lỗi tài liệu tham khảo của tôi là như sau:

struct Cpfs *cpfs = calloc(1, sizeof(*cpfs)); 

mà trong MSVC sản xuất:

Lỗi C2440 2 lỗi: 'khởi': không thể chuyển đổi từ 'void *' thành 'Cpfs *' e: \ src \ cpfs \ cpfs.c 179

Rõ ràng tôi không thể sử dụng new hoặc static_cast mà tôi tự nhiên muốn sử dụng nếu tôi đã không còn sử dụng C. Cách tốt nhất để cung cấp sự an toàn tối đa kiểu xung quanh void * cho mỗi ngôn ngữ với độ dài tối thiểu là gì?

+4

Tại sao bạn cần chuyển sang tập hợp con C và C++ chung? Như bạn đã phát hiện ra nó hạn chế nghiêm trọng những gì C (cách khác những gì C + +) bạn có thể sử dụng. Hầu như tất cả các môi trường có sẵn C++ cũng có sẵn C và cũng cho phép bạn liên kết các tệp đối tượng C++ và C với nhau. Tôi không thể nhìn thấy những gì bạn nhận được bằng cách chuyển đến tập con chung. –

+0

Đối với * loại an toàn trong C * (mà là một chút khó khăn), thực hiện một chức năng cho mỗi cấu trúc mà công việc là phân bổ và trả về một con trỏ đến một cấu trúc mới. Tương tự như vậy, hãy tạo một hàm để giải phóng cấu trúc. – rwong

+1

Tôi muốn biết lý do để cố viết một chương trình biên dịch cho hai ngôn ngữ khác nhau. Đó thường là một cái gì đó còn lại cho câu đố. – GManNickG

Trả lời

0

Có lẽ một cái gì đó như thế này? (Chưa được kiểm tra, không có trình biên dịch có sẵn, không sử dụng macro rất thường xuyên):

#ifdef __cplusplus 
    #define pointer_cast(type, pointer) reinterpret_cast<type>(pointer) 
#else 
    #define pointer_cast(type, pointer) (type)(pointer) 
#endif 
+0

Tại sao không chỉ tránh hoàn toàn diễn viên vô dụng khi '__cplusplus' không được xác định? –

+0

Tôi đã tạo một macro VOID_CAST chỉ diễn ra khi cần thiết. –

5

Tôi muốn đề xuất đơn giản bằng cách sử dụng phôi kiểu C hoặc gói phôi trong macro mở rộng thành không (trong C) hoặc static_cast bằng C++.

+3

Một 'reinterpret_cast' từ' void * 'không phải là diễn viên tốt nhất. 'static_cast' là đủ và ít có khả năng âm thầm truyền một nguồn không hợp lệ đến một kiểu con trỏ. –

+0

@Charles Bailey: Ok, đã chỉnh sửa. – Hasturkun

0

Giải pháp duy nhất tôi biết là để làm đúc rõ ràng:

struct Cpfs *cpfs = (Cpfs*)calloc(1, sizeof(*cpfs)); 

đây cả hai trình biên dịch được thỏa mãn. Cũng cần nhớ rằng, đối với các trình biên dịch cũ hơn thì malloc có thể trả về char *.

hth

Mario

0

làm một chức năng thay thế cấp phát mà bạn có thể định nghĩa khác nhau cho C và C++ xây dựng: - Một cái gì đó như thế này trong một tập tin tiêu đề:

#ifdef __cplusplus 
template<typename TypeT> 
TypeT* MyAlloc(TypeT** pOut,size_t cb){ 
    *pOut = static_cast<TypeT*>(malloc(cb)); //aint c++ pretty. 
    return *pOut; 
} 
#else 
    extern void* MyAlloc(void** ppv, size_t cb); 
#endif 

Bây giờ bạn có, trong C++ bản dựng, một hàm có thể suy ra loại điều mà nó xử lý, và trong bản dựng C, một hàm bình thường của nó trả về một khoảng trống *.

Vấn đề duy nhất là cần phải vượt qua trong con trỏ để cấp phát - trình biên dịch C++ sẽ không cố gắng suy ra một tham số mẫu chỉ dựa trên kiểu trả về của hàm afaik.Vì vậy, bạn có thể gọi nó là agnostically như thế này: -

int *p; 
if(MyAlloc(&p,sizeof(int)*n)){ 
    ... 
+0

"// aint C++ đẹp". Vâng, khi bạn sử dụng 'mới'. – GManNickG

+1

'mới' thậm chí còn tồi tệ hơn khi trình biên dịch C++ không suy ra các tham số mẫu lớp từ lời gọi hàm tạo. Vì vậy, tôi đã phải viết một cái gì đó như thế này ngày khác: 'SomeClass * pWrapper = new SomeOtherClass (phương thức này, & SomeOtherClass ::); ' –

+0

C++ không bao giờ là đẹp. –

2

Nếu trình biên dịch của bạn hỗ trợ decltype(), bạn có thể sử dụng một số phép thuật vĩ mô để tránh việc phải lặp lại một cách rõ ràng tên loại (và, nhờ sizeof, kích thước phần tử):

#ifdef __cplusplus 
#define my_calloc(VAR, COUNT) \ 
    static_cast<decltype(VAR)>(std::calloc(COUNT, sizeof *VAR)) 
#else 
#define my_calloc(VAR, COUNT) calloc(COUNT, sizeof *VAR) 
#endif 

sử dụng Ví dụ:

#ifdef __cplusplus 
#include <cstdlib> 
#else 
#include <stdlib.h> 
#endif 

struct Cpfs *cpfs = my_calloc(cpfs, 42); 

giải pháp sạch hơn có lẽ sẽ chỉ sử dụng một trình biên dịch C và liên kết các tập tin đối tượng, mặc dù ...

+0

decltype trông tương tự như typeof, sử dụng trình biên dịch c không phải là một tùy chọn, msvc không hỗ trợ c99.C++ biên dịch nó tốt hơn so với một trình biên dịch c half-assed –

+1

@Matt: bạn có thể sử dụng MinGW để biên dịch phần C của dự án của bạn và vẫn sử dụng MSVC cho phần C++ (xem ví dụ http://stackoverflow.com/questions/2096519/ từ-mingw-static-library-a-to-visual-studio-static-library-lib) – Christoph

+0

@Matt Joiner: lập trình cho giao điểm của C99 và C++ không khác biệt đáng kể so với lập trình C89, nó chỉ khó xử hơn và làm phiền. Bạn đang viết cho một phiên bản half-assed của C vì nó là, bằng cách sử dụng một trình biên dịch C half-assed không phải là bất kỳ tồi tệ hơn, và ít nhất là C89 của một tiêu chuẩn. –