2012-05-09 31 views
12

Sử dụng phổ biến typedefs là cho phép 'loại' của một biến để truyền đạt ý tưởng tốt hơn về mục đích của biến mà không cần định nghĩa lại cấu trúc lưu trữ đằng sau nó.Typedefs và specifier định dạng printf

Tuy nhiên, tôi cũng thấy typedef là cách thay đổi cấu trúc lưu trữ cho một lớp biến trong một lần.

Ví dụ, nếu tôi xác định

typedef uint32_t my_offset_t 

và có các biến của các loại my_offset_t, chuyển đổi mã-base từ uint32_t để char hoặc uint64_t cũng đơn giản như thay đổi một dòng và biên dịch lại (giả sử tôi đã đã sử dụng sizeof thay vì kích thước được mã hóa cứng), ngoại trừ trường hợp printf/scanf.

Có cách nào để trao đổi định dạng-specifiers theo loại một cách dễ dàng, mà không có chức năng wrapper xung quanh printf/scanf, if-elses, hoặc ifdefs?

Cảm ơn!

Đối với bất kỳ ai quan tâm, tôi đang sửa đổi LKM đã sử dụng bù lệch 16 bit để làm việc với bù bit 32 bit, nhưng muốn nó có thể chuyển sang bù đắp 64 bit (hoặc thứ khác) nếu cần với những thay đổi tối thiểu.

Trả lời

9

Đó là một doanh nghiệp phức tạp, nhưng <inttypes.h> từ C99 và sau đó cho biết cách thực hiện.

Đối với mỗi loại được xác định, bạn cần cung cấp cho mình một tập hợp các macro 'PRI' và 'SCN' thích hợp, cẩn thận để tránh không gian tên được chuẩn hóa.

Ví dụ, bạn có thể sử dụng XYZ như một tiền tố dự án cụ thể, và sản xuất:

XYZ_PRIx_my_offset_t 
XYZ_PRId_my_offset_t 
XYZ_PRIX_my_offset_t 
XYZ_PRIu_my_offset_t 
XYZ_PRIo_my_offset_t 

và các khoản tương đương SCN. Hơn nữa, bạn muốn xác định này trong điều khoản của các macro tương đương cho các loại hình cơ sở, vì vậy:

#define XYZ_PRIx_my_offset_t PRIx32 
#define XYZ_PRId_my_offset_t PRId32 
#define XYZ_PRIX_my_offset_t PRIX32 
#define XYZ_PRIu_my_offset_t PRIu32 
#define XYZ_PRIo_my_offset_t PRIo32 

Trong code của bạn, bạn xây dựng chuỗi định dạng của bạn bằng cách sử dụng XYZ_PRIx_my_offset_t macro:

printf("Offset: 0x%.8" XYZ_PRIX_my_offset_t "\n", my_offset_value); 

Nếu sau đó bạn cần phải thay đổi mọi thứ thành 64-bit, bạn chỉnh sửa typedef và các định nghĩa macro một cách thích hợp và phần còn lại của mã vẫn là 'không thay đổi'. Nếu bạn thực sự cẩn thận, bạn có thể nhận được khá gần hoàn toàn không thay đổi.

Đảm bảo bạn biên dịch trên cả hệ thống 32 bit và 64 bit với nhiều cảnh báo được đặt. GCC sẽ không cảnh báo về các vấn đề không phải trên nền tảng hiện tại của bạn, nhưng chúng có thể hiển thị trên nền tảng khác. (Tôi chỉ cố định một số mã đã được làm sạch trên 64-bit nhưng ô uế cho 32-bit, bây giờ nó sử dụng một vĩ mô như XYZ_PRId_int4 thay vì %d và biên dịch sạch trên cả hai.)

7

Nếu bạn nhìn vào earlier question on inttypes.h của mình, bạn có thể xem cách định danh hệ thống định dạng có thể được sử dụng phù hợp với typedefs (thông qua #define) để thực hiện tùy chỉnh in specifiers cho các loại tùy chỉnh của bạn.

+0

Cảm ơn cho câu trả lời :) Tôi chấp nhận người kia mặc dù bởi vì nó là một phản ứng hoàn thiện hơn, trong trường hợp bất cứ ai khác quan tâm đến câu hỏi này. – Vanwaril

0

Một giải pháp khác là chuyển đổi thành và từ intmax_t đối với các loại đã ký và uintmax_t cho các loại chưa ký. Ví dụ:

printf("%ju\n", (uintmax_t)n); 

sẽ hoạt động chính xác nếu n là bất kỳ loại không dấu nào.

Đối với các chức năng *scanf(), bạn phải đọc vào một đối tượng tạm thời và sau đó gán.

(Điều này giả định thư viện thời gian chạy của bạn hỗ trợ tính năng này.)