2009-07-26 14 views
16

Trong khi nghiên cứu cách thực hiện các chuỗi định dạng chéo printf() trong C (nghĩa là, có tính đến số lượng bit mà tôi mong đợi mỗi đối số nguyên cho printf() nên) Tôi chạy qua this section of the Wikipedia article on printf(). Bài viết bàn về tùy chọn phi tiêu chuẩn có thể được truyền cho printf() chuỗi định dạng, chẳng hạn như (những gì có vẻ là một phần mở rộng của Microsoft cụ thể):Tại sao các chuỗi tùy chọn mới (chiều rộng bit cụ thể) printf() định dạng được chấp nhận như là một phần của C99?

printf("%I32d\n", my32bitInt); 

Nó tiếp tục nói rằng:

ISO C99 bao gồm tiêu đề inttypes.h tệp bao gồm một số macro để sử dụng trong mã hóa độc lập nền tảng .

... và sau đó liệt kê một tập hợp các macro có thể tìm thấy trong tiêu đề đã nói. Nhìn vào tập tin tiêu đề, để sử dụng chúng tôi sẽ phải viết:

printf("%"PRId32"\n", my32bitInt); 

Câu hỏi của tôi là: Tôi đang thiếu cái gì? Đây có phải là cách C99 tiêu chuẩn để làm điều đó không? Nếu vậy, tại sao? (Mặc dù tôi không ngạc nhiên khi tôi chưa bao giờ thấy mã sử dụng các chuỗi định dạng theo cách này, vì nó có vẻ quá cồng kềnh ...)

Trả lời

16

C Lý do dường như ngụ ý rằng <inttypes.h> được tiêu chuẩn hóa thực hiện:

<inttypes.h> được bắt nguồn từ tiêu đề cùng tên được tìm thấy trên một vài 64-bit hiện tại hệ thống.

nhưng phần còn lại của văn bản không viết về các macro đó và tôi không nhớ chúng là thực tế hiện tại vào thời điểm đó.

Điều sau chỉ là suy đoán, nhưng được giáo dục bằng kinh nghiệm về cách các ủy ban tiêu chuẩn hóa hoạt động.

Một lợi thế của các macro C99 so với tiêu chuẩn hóa định dạng bổ sung cho printf (lưu ý rằng C99 cũng đã thêm một số) là cung cấp <inttypes.h><stdint.h> khi bạn đã thực hiện hỗ trợ các tính năng bắt buộc theo cách thực hiện cụ thể. hai tệp có typedef và macro đầy đủ. Điều đó làm giảm chi phí thực hiện tuân thủ hiện tại, giảm nguy cơ phá vỡ các chương trình hiện có sử dụng các tính năng cụ thể hiện có (cách tiêu chuẩn không can thiệp) và tạo điều kiện cho việc chuyển các chương trình tuân thủ để thực hiện những người không có tiêu đề (chúng có thể được cung cấp bởi chương trình). Ngoài ra, nếu các cách thực hiện cụ thể đã được thay đổi vào thời điểm đó, nó không có lợi cho việc triển khai thực hiện khác.

+0

Một nhược điểm: gọi C từ hội đồng. –

8

Chính xác, đây là cách chuẩn C99 cho biết bạn nên sử dụng chúng. Nếu bạn muốn mã portablt thực sự phù hợp với tiêu chuẩn 100% đối với chữ cái, bạn phải luôn in int bằng cách sử dụng "%d"int32_t sử dụng "%"PRId32.

Hầu hết mọi người sẽ không bận tâm, tuy nhiên, vì có rất ít trường hợp không làm như vậy sẽ thành vấn đề. Trừ khi bạn đang chuyển mã của mình sang Win16 hoặc DOS, bạn có thể giả định rằng sizeof(int32_t) <= sizeof(int), do đó vô hại khi vô tình in một số int32_t dưới dạng int. Tương tự, long long có khá nhiều 64 bit (mặc dù nó không được đảm bảo như vậy), do đó, hãy in int64_t làm long long (ví dụ: với một mã thông số %llx) cũng an toàn.

Các loại int_fast32_t, int_least32_t, et al hầu như không bao giờ được sử dụng, vì vậy bạn có thể tưởng tượng rằng các trình định dạng định dạng tương ứng của chúng được sử dụng ít khi hiếm hơn.

+0

"Câu hỏi của tôi là: Tôi thiếu một cái gì đó? Đây có phải là cách C99 tiêu chuẩn để làm điều đó không? ** Nếu vậy, tại sao? **" –

+0

Mặc dù tôi thực sự muốn biết phần "tại sao", tôi nhận ra rằng nó là một phần của một câu hỏi tu từ. Tôi nghi ngờ bất cứ ai sẽ biết, trừ khi họ tham dự cuộc thảo luận tại các tổ chức tiêu chuẩn khi C99 được nói đến. Tôi đang chụp ảnh một loạt các kỹ sư thảo luận về giá trị của việc yêu cầu thay đổi đối với printf() khi họ đã có chuỗi định dạng để in bất kỳ thứ gì. Có lẽ họ đã quyết định biến nó thành #define và được thực hiện với nó. Vì vậy, trừ khi người khác có một số thông tin chi tiết sâu sắc ở đây, tôi có thể sẽ chấp nhận câu trả lời này; nó trả lời hầu hết câu hỏi của tôi. – mpontillo

+1

Có lẽ tôi viết quá nhiều mã nhúng, nhưng tôi là một fan hâm mộ lớn của việc sử dụng các macro «PRIx ##' trong chuỗi printf của tôi. Tôi chỉ cho rằng 'int' là 16 bit hoặc lớn hơn. Một khi bạn đã thực hiện nó một thời gian, bạn đã quen với nó. – tomlogic

1

Tôi chỉ có thể suy đoán tại sao. Tôi thích câu trả lời của AProgrammer ở ​​trên, nhưng có một khía cạnh bị bỏ qua: bạn sẽ thêm gì vào printf như một công cụ sửa đổi định dạng? Đã có hai cách khác nhau mà các số được sử dụng trong một chuỗi định dạng printf (chiều rộng và độ chính xác). Thêm một loại thứ ba của số để nói có bao nhiêu bit chính xác trong đối số sẽ là tuyệt vời, nhưng bạn sẽ đặt nó ở đâu mà không gây nhầm lẫn cho mọi người? Đáng tiếc là một trong những sai sót trong C là printf không được thiết kế để có thể mở rộng được.

Các macro là khủng khiếp, nhưng khi bạn phải viết mã di động trên nền tảng 32 bit và 64 bit, chúng là một ơn trời. Chắc chắn đã cứu thịt xông khói của tôi.

Tôi nghĩ rằng câu trả lời cho câu hỏi của bạn tại sao là một trong hai

  • Không ai có thể nghĩ ra một cách tốt hơn để làm điều đó, hoặc
  • Ủy ban tiêu chuẩn không thể đồng ý về bất cứ điều gì họ cảm thấy được rõ ràng tốt hơn.
+0

Điểm tốt, nhưng Microsoft đã thêm một cách để làm điều đó bằng cách sử dụng một công cụ sửa đổi định dạng (mà là xấu xí nhưng nó hoạt động). Một cách có thể là tách suy nghĩ "d = int, u = unsigned int" hiện tại và gán lại các kiểu chỉ định kiểu như "d = int32_t, u = uint32_t". Điều đó có thể ít gây rối hơn C so với tuyến Java. (chỉ định chiều rộng bit của mỗi loại một cách rõ ràng - mà họ có lẽ nên đã làm ban đầu ...) Nhưng nó vẫn sẽ có yêu cầu thay đổi để printf() hiện thực. Tôi nghĩ rằng họ chỉ cần thực hiện một cách dễ dàng. – mpontillo

+0

@Mike: bạn có con trỏ theo cách của Microsoft không? Tôi ghét các macro. Và tôi đã thực hiện hầu hết việc triển khai printf. –

+0

Nó đã được đề cập trên bài viết Wikipedia tôi liên kết, nhưng ở đây nó là trực tiếp từ nguồn: http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx – mpontillo

1

Khả năng khác: tương thích ngược. Nếu bạn thêm nhiều định dạng định dạng khác vào printf hoặc các tùy chọn bổ sung, có thể một trình chỉ định trong một số mã C99 trước sẽ có chuỗi định dạng được diễn giải khác nhau.

Với thay đổi C99, bạn không thay đổi chức năng của printf.

2

Bạn luôn có thể truyền lên trên và sử dụng %jd là định dạng số intmax_t.

printf("%jd\n", (intmax_t)(-2)); 

tôi đã sử dụng intmax_t để chứng minh rằng bất kỳ intXX_t có thể được sử dụng, nhưng chỉ đơn giản là đúc để long là tốt hơn nhiều đối với trường hợp int32_t, sau đó sử dụng %ld.

+0

+1 cho ý tưởng thú vị, nhưng tôi không chắc tôi thích ý tưởng về khả năng truyền số nguyên 32 bit đến giá trị 64 bit + trên hệ thống nhúng ... chỉ cảm thấy sai bằng cách nào đó. ;-) – mpontillo

+0

khi bạn đang sử dụng 'printf', lãng phí 4 byte để lưu trữ tạm thời (nếu có) là vấn đề hiệu suất ít nhất của bạn! ;) – lambdapower

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