Tôi nên in các loại như off_t và size_t như thế nào?


148

Tôi đang cố gắng in các loại như off_tsize_t. Giữ chỗ chính xác cho printf() đó là di động là gì?

Hoặc có một cách hoàn toàn khác để in các biến đó?


2
@devin: Tôi tin rằng tôi đã phát hiện ra rằng loại trong khi sử dụng fopen, fseekvv trên Mac OS X. off_tđược sử dụng để bù đắp.
Georg Schölly

Câu trả lời:


112

Bạn có thể sử dụng zcho size_t và tcho ptrdiff_t như trong

printf("%zu %td", size, ptrdiff);

Nhưng trang của tôi nói rằng một số thư viện cũ đã sử dụng một ký tự khác zvà không khuyến khích sử dụng nó. Tuy nhiên, nó được chuẩn hóa (theo tiêu chuẩn C99). Đối với những người intmax_tint8_tcủa stdint.hvà như vậy, có macro bạn có thể sử dụng, như câu trả lời khác nói:

printf("value: %" PRId32, some_int32_t);
printf("value: %" PRIu16, some_uint16_t);

Chúng được liệt kê trong trang của inttypes.h.

Cá nhân, tôi sẽ chỉ đưa ra các giá trị unsigned longhoặc longgiống như một câu trả lời khác khuyến nghị. Nếu bạn sử dụng C99, thì dĩ nhiên, bạn có thể (và nên) chuyển sang unsigned long longhoặc long longvà sử dụng các định dạng %lluhoặc %lldđịnh dạng tương ứng.


2
off_t thực sự là một chữ ký dài dài trên hệ thống của tôi.
Georg Schölly

2
Tôi nghĩ rằng trang man không khuyến khích sử dụng Z (chữ hoa) được libc5 sử dụng. Nó dường như không khuyến khích z (chữ thường).
Draemon

12
Sử dụng %zdvới a size_thành vi không xác định do sự không phù hợp về chữ ký (C99 7.19.6.1 # 9). Nó phải như vậy %zu.
Jens

7
Chà, làm sao để in off_t rồi?
JohnyTex

3
@ Jens Tôi không thấy làm thế nào %zdvới một size_thành vi không xác định từ đoạn đó hoặc từ bất kỳ khác. Trong thực tế, định nghĩa của %z# 7 cho phép rõ ràng %dvới size_tvà loại đã ký tương ứng và §6.2.5 # 9 cho phép sử dụng rõ ràng các giá trị của các loại không dấu trong đó loại được ký tương ứng được dự kiến, miễn là giá trị là giá trị không âm hợp lệ của loại đã ký.
Chortos-2

108

Để in off_t:

printf("%jd\n", (intmax_t)x);

Để in size_t:

printf("%zu\n", x);

Để in ssize_t:

printf("%zd\n", x);

Xem 7.19.6.1/7 trong tiêu chuẩn C99 hoặc tài liệu mã định dạng POSIX thuận tiện hơn:

http://pub.opengroup.org/onlinepub/009695399/fifts/fprintf.html

Nếu việc triển khai của bạn không hỗ trợ các mã định dạng đó (ví dụ vì bạn đang sử dụng C89), thì bạn có một chút vấn đề vì AFAIK không có loại số nguyên trong C89 có mã định dạng và được đảm bảo là lớn như những loại này. Vì vậy, bạn cần phải làm một cái gì đó cụ thể thực hiện.

Ví dụ: nếu trình biên dịch của bạn có long longvà thư viện chuẩn của bạn hỗ trợ %lld, bạn có thể tự tin mong đợi rằng nó sẽ phục vụ thay thế intmax_t. Nhưng nếu không, bạn sẽ phải quay lại long, điều này sẽ thất bại đối với một số triển khai khác vì nó quá nhỏ.


3
Đây là câu trả lời tốt hơn, tôi đã quên mất việc sử dụng% zu cho size_t không dấu. Và truyền tới intmax_t là một giải pháp tuyệt vời cho bất kỳ off_t nào trên bất kỳ nền tảng nào.
Peter Cordes

2
POSIX không đảm bảo ssize_tcó cùng kích thước size_t, vì vậy mã thực sự di động nên chuyển đổi nó thành intmax_tvà in %jdgiống như vậy off_t.
nwellnhof

off_t có thể dài tối đa kích thước và có thể thay đổi tùy theo định nghĩa ... Visual Studio cũng cảnh báo với điều này "cảnh báo C4477: '_snprintf_s': chuỗi định dạng '% jd' yêu cầu đối số loại '__int64', nhưng đối số biến đổi 1 có loại 'off_t' "... Một cách thực sự di động là printf ("% lld \ n ", (dài dài) x);
ericcurtin

5

Đối với Microsoft, câu trả lời là khác nhau. VS2013 phần lớn tuân thủ C99 nhưng "[t] he hh, j, z và t tiền tố không được hỗ trợ." Đối với size_t "nghĩa là, không dấu __int32 trên nền tảng 32 bit, không dấu __int64 trên nền tảng 64 bit" sử dụng tiền tố I (con mắt vốn) với công cụ xác định loại o, u, x hoặc X. Xem thông số Kích thước VS2013

Đối với off_t, nó được định nghĩa là dài trong VC \ include \ sys \ type.h.


Lưu ý nếu off_tluôn luôn longlà nó sẽ làm cho nó 32 bit (thậm chí Windows 64 bit sử dụng 32 bit cho long).
sourcejedi

3

Bạn đang sử dụng phiên bản nào của C?

Trong C90, thông lệ tiêu chuẩn là chuyển sang ký dài hoặc không dấu, nếu phù hợp và in tương ứng. Tôi đã thấy% z cho size_t, nhưng Harbison và Steele không đề cập đến nó trong printf () và trong mọi trường hợp sẽ không giúp bạn với ptrdiff_t hoặc bất cứ điều gì.

Trong C99, các loại _t khác nhau đi kèm với các macro printf của riêng chúng, vì vậy một số thứ như "Size is " FOO " bytes." tôi không biết chi tiết, nhưng đó là một phần của định dạng số khá lớn bao gồm tệp.


3

Bạn sẽ muốn sử dụng các macro định dạng từ inttypes.h.

Xem câu hỏi này: Chuỗi định dạng nền tảng chéo cho các biến loại size_t?


Giả sử off_t là một int có kích thước con trỏ đã ký (tôi không biết định nghĩa chính xác là gì) như ptrdiff_t thì bạn sẽ sử dụng PRIdPTR hoặc PRIiPTR.
Michael Burr

11
Các off_tloại lớn hơn một con trỏ trên bất kỳ hệ thống 32-bit hỗ trợ các file lớn (đó là hầu hết các hệ 32-bit những ngày này).
Dietrich Epp

1
@DietrichEpp: Thật ra, nó còn tệ hơn thế nữa; nhiều hệ thống 32 bit có cả off_t và off64_t, và tùy thuộc vào các tính năng macro off_t có thể thực sự có nghĩa là off64_t.
SamB

1

Nhìn man 3 printfvào Linux, OS X và OpenBSD đều hiển thị hỗ trợ %zcho size_t%tchoptrdiff_t (cho C99), nhưng không ai trong số đó đề cập đến off_t. Các đề xuất trong tự nhiên thường cung cấp %uchuyển đổi cho off_t, "đủ chính xác" theo như tôi có thể nói (cả hai unsigned intoff_tkhác nhau giữa các hệ thống 64 bit và 32 bit).


1
Hệ thống của tôi (OS X) có 32 bit unsigned intvà 64 bit off_t. Vì vậy, các diễn viên sẽ làm mất dữ liệu.
Dietrich Epp

-3

Tôi đã thấy bài đăng này ít nhất hai lần, bởi vì câu trả lời được chấp nhận là khó nhớ đối với tôi (tôi hiếm khi sử dụng zhoặc gắn jcờ và chúng dường như không độc lập với nền tảng ).

Các tiêu chuẩn không bao giờ nói rõ chiều dài dữ liệu chính xác của size_t, vì vậy tôi đề nghị đầu tiên bạn nên kiểm tra chiều dài size_ttrên nền tảng của bạn sau đó chọn một trong số họ:

if sizeof(size_t) == 4 use PRIu32
if sizeof(size_t) == 8 use PRIu64

Và tôi đề nghị sử dụng stdintcác loại thay vì các loại dữ liệu thô cho thống nhất.


1
Đối với C99 và C11, tiêu chuẩn rõ ràng %zucó thể được sử dụng để in size_tcác giá trị. Người ta phải chắc chắn không phải nghỉ mát để sử dụng một uint32_t/ uint64_tformat specifier in một size_t, như không có gì bảo đảm rằng những loại tương thích.
tự kỷ

-4

Như tôi nhớ, cách di động duy nhất để làm điều đó là sử dụng kết quả thành "unsign long int" và sử dụng %lu.

printf("sizeof(int) = %lu", (unsigned long) sizeof(int));

1
Phải là "% lu", vì công cụ sửa đổi độ dài sẽ xuất hiện trước khi chuyển đổi.
dwc

1
off_t ví dụ là một ký dài dài.
Georg Schölly

@ GeorgSchölly - Sau đó, bạn đã đạt được một câu hỏi hóc búa, vì long longkhông tồn tại trong tiêu chuẩn C ++, và do đó vốn dĩ không thể mang theo được.
James Curran

-9

sử dụng "% zo" cho off_t. (bát phân) hoặc "% zu" cho số thập phân.


Tại sao bạn muốn tập tin bù vào bát phân?
poolie
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.