2008-12-17 26 views
32

Có cách nào để thực thi dàn diễn viên rõ ràng cho typedef cùng loại không? Tôi đã đối phó với utf8 và đôi khi tôi bị lẫn lộn với các chỉ số về số ký tự và số byte. Vì vậy, nó là tốt đẹp để có một số typedefs:Thực thi kiểm tra kiểu mạnh trong C (loại độ chính xác cho typedefs)

typedef unsigned int char_idx_t; 
typedef unsigned int byte_idx_t; 

Với việc bổ sung mà bạn cần một diễn viên rõ ràng giữa chúng:

char_idx_t a = 0; 
byte_idx_t b; 

b = a; // compile warning 
b = (byte_idx_t) a; // ok 

Tôi biết rằng một tính năng như vậy không tồn tại trong C, nhưng có lẽ bạn biết một mẹo hoặc một phần mở rộng trình biên dịch (gcc thích hợp hơn) làm điều đó.


EDIT tôi vẫn không thực sự thích các ký hiệu Hungarian nói chung. Tôi không thể sử dụng nó cho vấn đề này vì các quy ước mã hóa dự án, nhưng bây giờ tôi đã sử dụng nó trong một trường hợp tương tự khác, nơi mà các kiểu giống nhau và ý nghĩa rất giống nhau. Và tôi phải thừa nhận: nó giúp. Tôi sẽ không bao giờ đi và khai báo mọi số nguyên với chữ "i" bắt đầu, nhưng như trong ví dụ của Joel cho các kiểu chồng chéo, nó có thể là sự cứu sống.

+2

Có một bài viết rất hay khác (Mặc dù tôi không đồng ý cấm goto :)) từ [Joel] (http://www.joelonsoftware.com/) có tên [Làm sai mã nhìn sai] (http://www.joelonsoftware.com/articles/Wrong.html). Tôi nghĩ rằng nó rất liên quan đến câu hỏi của bạn ngay cả khi không có kết nối trực tiếp. – Ilya

+0

Điều thú vị nhất và quan trọng nhất trong bài viết đó, IMHO, là một chút về lịch sử của ký hiệu Hungary. Veeery thú vị ... – Noein

Trả lời

2

Nếu bạn đang viết C++, bạn có thể tạo hai lớp được xác định giống hệt nhau với các tên khác nhau được bao bọc xung quanh một dấu int. Tôi không biết của một thủ thuật để làm những gì bạn muốn trong C.

+2

C hoạt động theo cùng một cách với cấu trúc. Microsoft sử dụng điều này để phân biệt các loại xử lý trong windows.h. –

18

Bạn có thể làm một cái gì đó như:

typedef struct { 
    unsigned int c_idx; 
} char_idx; 

typedef struct { 
    unsigned int b_idx; 
} byte_idx; 

Sau đó, bạn sẽ thấy khi bạn đang sử dụng mỗi:

char_idx a; 
byte_idx b; 

b.b_idx = a.c_idx; 

Bây giờ nó rõ ràng hơn rằng họ là các loại khác nhau nhưng vẫn sẽ biên dịch.

18

Đối với các loại "tay cầm" (con trỏ đục), Microsoft sử dụng trick của tuyên bố cấu trúc và sau đó typedef'ing một con trỏ đến cấu trúc:

#define DECLARE_HANDLE(name) struct name##__ { int unused; }; \ 
          typedef struct name##__ *name 

Sau đó, thay vì

typedef void* FOOHANDLE; 
typedef void* BARHANDLE; 

Họ làm:

DECLARE_HANDLE(FOOHANDLE); 
DECLARE_HANDLE(BARHANDLE); 

Vì vậy, bây giờ, công trình này:

FOOHANDLE make_foo(); 
BARHANDLE make_bar(); 
void do_bar(BARHANDLE); 

FOOHANDLE foo = make_foo(); /* ok */ 
BARHANDLE bar = foo;   /* won't work! */ 
do_bar(foo);     /* won't work! */ 
7

Sử dụng bút chì. Xem Splint:Typesstrong type check.

Kiểm tra loại mạnh thường tiết lộ lỗi lập trình. Nẹp có thể kiểm tra các kiểu C nguyên thủy chặt chẽ hơn và linh hoạt hơn các trình biên dịch điển hình (4.1) và cung cấp hỗ trợ kiểu Boolean (4.2). Ngoài ra, người dùng có thể xác định các loại trừu tượng cung cấp thông tin ẩn ẩn (0).

4

Trong C, chỉ phân biệt giữa các loại người dùng định nghĩa đó là thực thi bởi trình biên dịch là sự phân biệt giữa struct. Bất kỳ typedef nào liên quan đến các cấu trúc riêng biệt sẽ hoạt động. Câu hỏi thiết kế chính của bạn là các kiểu cấu trúc khác nhau có sử dụng cùng tên thành viên không? Nếu vậy, bạn có thể mô phỏng một số mã đa hình bằng cách sử dụng macro và các thủ thuật scurvy khác. Nếu không, bạn thực sự cam kết với hai đại diện khác nhau. Ví dụ, bạn có muốn để có thể

#define INCREMENT(s, k) ((s).n += (k)) 

và sử dụng INCREMENT trên cả byte_idxchar_idx? Sau đó, đặt tên cho các trường giống nhau.

3

Bạn đã hỏi về tiện ích. Jeff Foster của CQual là rất tốt đẹp, và tôi nghĩ rằng nó có thể làm công việc mà bạn muốn.

+0

Có các chương trình tương tự vẫn đang hoạt động (cập nhật lần cuối cho trang web của CQual là vào năm 2004) – CodeMonkey

14

Điều bạn muốn được gọi là "typedef mạnh" hoặc "typedef nghiêm ngặt".

Một số ngôn ngữ lập trình [Rust, D, Haskell, Ada, ...] cung cấp hỗ trợ cho ngôn ngữ này, C [++] thì không. Có một đề xuất để đưa nó vào ngôn ngữ có tên "opaque typedef", nhưng không được chấp nhận.

Việc thiếu hỗ trợ ngôn ngữ thực sự không phải là vấn đề. Chỉ cần bọc các loại để được aliased vào một lớp mới có chính xác 1 thành viên dữ liệu, loại T. Nhiều sự lặp lại có thể được factored ra bởi các mẫu và các macro. Kỹ thuật đơn giản này cũng tiện lợi như trong các ngôn ngữ lập trình với sự hỗ trợ trực tiếp.

2

Sử dụng typedef mạnh theo quy định tại BOOST_STRONG_TYPEDEF

+3

Boost là thư viện C++ và do đó không liên quan. – Porculus

1

Với C++ 11 bạn có thể sử dụng một lớp enum, ví dụ

enum class char_idx_t : unsigned int {}; 
enum class byte_idx_t : unsigned int {}; 

Trình biên dịch sẽ thực thi một diễn viên rõ ràng giữa hai loại; nó giống như một lớp bọc mỏng. Rất tiếc, bạn sẽ không bị quá tải toán tử, ví dụ: nếu bạn muốn thêm hai char_idx_t cùng nhau, bạn sẽ phải cast chúng vào int không dấu.

+0

Xem bản sửa đổi đề xuất (3) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf – qub1n

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