2012-01-31 37 views
42

Tôi đang gửi tệp từ máy khách đến máy chủ bằng TCP. Để đánh dấu phần cuối của tệp tôi muốn gửi kích thước tệp trước dữ liệu thực tế. Vì vậy, tôi sử dụng stat cuộc gọi hệ thống để tìm kích thước của tệp. Đây là loại off_t. Tôi thích biết bao nhiêu byte nó chiếm để tôi có thể đọc nó đúng cách ở phía máy chủ. Nó được định nghĩa trong <sys/types.h>. Nhưng tôi không hiểu định nghĩa. Nó chỉ xác định __off_t or _off64_toff_t. Tìm kiếm __off_t ở đâu? Ngoài ra, quy ước rằng __ là tiền tố cho hầu hết mọi thứ trong tệp tiêu đề và làm tôi sợ khi đọc tệp tiêu đề để hiểu rõ hơn. Làm cách nào để đọc tệp tiêu đề tốt hơn?Nơi để tìm định nghĩa đầy đủ của loại off_t?

#ifndef __off_t_defined 
# ifndef __USE_FILE_OFFSET64 
typedef __off_t off_t; 
# else 
typedef __off64_t off_t; 
# endif 
# define __off_t_defined 
#endif 
+5

Bất cứ điều gì bắt đầu với '__' được dành riêng để sử dụng thực hiện (trừ khi tiêu chuẩn định nghĩa một ý nghĩa cho nó, như trong '__func__' hoặc' __FILE__'). Mức độ vô hướng cho phép thực hiện xác định kiểu của riêng nó '__off_t' mà không can thiệp vào bất cứ điều gì bạn có thể làm một cách hợp pháp. Các bit cụ thể nền tảng của các tiêu đề sau đó có thể được ẩn tốt hơn (do đó, một bản sao của mã nguồn có thể xử lý các bản biên dịch 32 bit và 64 bit trên một máy đơn lẻ). Đọc tiêu đề chuẩn là một công việc chính vì có quá nhiều định nghĩa liên kết với nhau. –

Trả lời

54

Vì câu trả lời này vẫn được bình chọn, tôi muốn chỉ ra rằng bạn hầu như không bao giờ cần phải tìm trong tệp tiêu đề. Nếu bạn muốn viết mã đáng tin cậy, bạn sẽ phục vụ tốt hơn bằng cách xem xét tiêu chuẩn. Một câu hỏi hay hơn "cách off_t được xác định trên máy của tôi" là "cách off_t được xác định theo tiêu chuẩn?". Theo tiêu chuẩn có nghĩa là mã của bạn sẽ hoạt động ngày hôm nay và ngày mai, trên bất kỳ máy nào.

Trong trường hợp này, off_t không được xác định theo tiêu chuẩn C. Đó là một phần của tiêu chuẩn POSIX, trong đó you can browse here.

Thật không may, off_t không được xác định rất chặt chẽ. Tất cả tôi có thể tìm để xác định nó là trên trang trên sys/types.h:

blkcnt_toff_t được ký kiểu số nguyên.

Điều này có nghĩa là bạn không thể chắc chắn nó lớn như thế nào. Nếu bạn đang sử dụng GNU C, bạn có thể sử dụng các hướng dẫn trong the answer below để đảm bảo rằng nó là 64 bit. Hoặc tốt hơn, bạn có thể chuyển đổi thành kích thước được xác định tiêu chuẩn trước khi đặt nó lên dây. Đây là cách các dự án như công việc của Protocol Buffers của Google (mặc dù đó là dự án C++).


Vì vậy, tôi nghĩ "tôi tìm định nghĩa trong tệp tiêu đề của mình ở đâu" không phải là câu hỏi hay nhất. Nhưng, để hoàn thành, đây là câu trả lời:

Bạn sẽ tìm thấy định nghĩa trong bits/types.h (như nhận xét ở trên cùng, không bao giờ trực tiếp bao gồm tệp này), nhưng nó bị che khuất một chút trong một loạt các macro. Một thay thế cho cố gắng để làm sáng tỏ họ là nhìn vào sản lượng tiền xử lý:

#include <stdio.h> 
#include <sys/types.h> 

int main(void) { 
    off_t blah; 

    return 0; 
} 

Và sau đó:

$ gcc -E sizes.c | grep __off_t 
typedef long int __off_t; 
.... 

Tuy nhiên, nếu bạn muốn biết kích thước của một cái gì đó, bạn luôn có thể sử dụng sizeof() nhà điều hành.

Chỉnh sửa: Chỉ cần nhìn thấy một phần câu hỏi của bạn về số __. This answer has a good discussion. Điểm mấu chốt là tên bắt đầu bằng __ được dành riêng cho việc triển khai (vì vậy bạn không nên bắt đầu định nghĩa của riêng mình với __).

+0

Tôi sử dụng kích thước của trên off_t. Trên máy tính của tôi (client) nó là 4 byte. Kích thước tệp tối đa tôi có thể biểu thị là 2^32 byte. Điều đó có phù hợp với kích thước off_t trên máy chủ của tôi trong trường hợp cụ thể này không. Tôi không nên tin. – FourOfAKind

+1

Đúng là 'off_t' có thể có kích thước khác nhau trên các máy khác nhau (hoặc trình biên dịch).Lưu ý rằng trong GCC, bạn có thể sử dụng '-D_FILE_OFFSET_BITS = 64' để lấy các định nghĩa' byte 'và' size_t' 8 byte. –

+0

Ok.So máy chủ nên tìm 4 byte đầu tiên hoặc 8 byte đầu tiên để có được độ dài của tệp. – FourOfAKind

26

Là "GNU C Library Reference Manual" nói

off_t 
    This is a signed integer type used to represent file sizes. 
    In the GNU C Library, this type is no narrower than int. 
    If the source is compiled with _FILE_OFFSET_BITS == 64 this 
    type is transparently replaced by off64_t. 

off64_t 
    This type is used similar to off_t. The difference is that 
    even on 32 bit machines, where the off_t type would have 32 bits, 
    off64_t has 64 bits and so is able to address files up to 2^63 bytes 
    in length. When compiling with _FILE_OFFSET_BITS == 64 this type 
    is available under the name off_t. 

Vì vậy, nếu bạn muốn cách đáng tin cậy đại diện cho kích thước tập tin giữa máy khách và máy chủ, bạn có thể:

  1. Sử dụng off64_t loại và stat64() chức năng phù hợp (vì nó lấp đầy cấu trúc stat64, trong đó có chứa off64_t loại chính nó). Loại off64_t bảo hành cùng kích thước trên các máy 32 bit và 64 bit.
  2. Như đã được đề cập trước khi biên dịch mã của bạn với -D_FILE_OFFSET_BITS == 64 và sử dụng thông thường off_tstat().
  3. Chuyển đổi off_t để nhập int64_t với kích thước cố định (chuẩn C99). Lưu ý: (sách của tôi 'C in a Nutshell' nói rằng đó là tiêu chuẩn C99, nhưng tùy chọn khi triển khai). Các tiêu chuẩn C11 mới nhất nói:

    7.20.1.1 Exact-width integer types 
    1 The typedef name intN_t designates a signed integer type with width N , 
    no padding bits, and a two’s complement representation. Thus, int8_t 
    denotes such a signed integer type with a width of exactly 8 bits. 
    without mentioning. 
    

    Và về thực hiện:

    7.20 Integer types <stdint.h> 
    ... An implementation shall provide those types described as ‘‘required’’, 
    but need not provide any of the others (described as ‘‘optional’’). 
    ... 
    The following types are required: 
    int_least8_t uint_least8_t 
    int_least16_t uint_least16_t 
    int_least32_t uint_least32_t 
    int_least64_t uint_least64_t 
    All other types of this form are optional. 
    

Như vậy, nói chung, tiêu chuẩn C có thể không đảm bảo loại với kích thước cố định. Nhưng hầu hết các trình biên dịch (bao gồm cả gcc) đều hỗ trợ tính năng này.

+2

thông tin tốt đẹp. +1 – loulou

+0

Tôi đã chỉnh sửa câu trả lời theo nhận xét của bạn. Cảm ơn! – likern

2

Nếu bạn đang gặp khó khăn khi truy tìm các định nghĩa, bạn có thể sử dụng đầu ra được xử lý trước của trình biên dịch sẽ cho bạn biết tất cả những gì bạn cần biết. Ví dụ.

$ cat test.c 
#include <stdio.h> 
$ cc -E test.c | grep off_t 
typedef long int __off_t; 
typedef __off64_t __loff_t; 
    __off_t __pos; 
    __off_t _old_offset; 
typedef __off_t off_t; 
extern int fseeko (FILE *__stream, __off_t __off, int __whence); 
extern __off_t ftello (FILE *__stream) ; 

Nếu bạn nhìn vào đầu ra hoàn tất, bạn thậm chí có thể thấy vị trí tập tin header và dòng con số chính xác nơi nó được định nghĩa:

# 132 "/usr/include/bits/types.h" 2 3 4 


typedef unsigned long int __dev_t; 
typedef unsigned int __uid_t; 
typedef unsigned int __gid_t; 
typedef unsigned long int __ino_t; 
typedef unsigned long int __ino64_t; 
typedef unsigned int __mode_t; 
typedef unsigned long int __nlink_t; 
typedef long int __off_t; 
typedef long int __off64_t; 

...

# 91 "/usr/include/stdio.h" 3 4 
typedef __off_t off_t; 
3

Nếu bạn đang viết mã di động, câu trả lời là "bạn không thể nói", tin tốt là bạn không cần. Giao thức của bạn nên liên quan đến việc viết kích thước như (ví dụ) "8 octet, định dạng lớn-endian" (Lý tưởng là với một kiểm tra kích thước thực tế phù hợp với 8 octet.)

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