Tại sao tiêu chuẩn C ++ xử lý tệp tìm kiếm theo cách của nó?


17

C ++ sử dụng streamoffloại để biểu thị phần bù trong luồng (tệp) và được định nghĩa như sau trong [stream.types]:

using streamoff = implementation-defined ;

Streamoff loại là một từ đồng nghĩa cho một trong các loại tích phân cơ bản đã ký có kích thước đủ để thể hiện kích thước tệp tối đa có thể cho hệ điều hành. 287)

287) Điển hình là dài dài.

Điều này có ý nghĩa bởi vì nó cho phép tìm kiếm trong các tệp lớn (trái ngược với việc sử dụng long, có thể chỉ rộng 32 bit).

[filebuf.virtuals] xác định basic_filebufchức năng tìm kiếm trong một tệp như sau:

pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override;

off_typetương đương với streamoff, xem [iostreams.limits.pose]. Tuy nhiên, tiêu chuẩn sau đó tiếp tục để giải thích các hiệu ứng của chức năng. Tôi bị kích thích bởi câu cuối cùng, đòi hỏi một cuộc gọi đến fseek:

Tác dụng : Hãy widthbiểu thị a_codecvt.encoding(). Nếu is_open() == false, hoặc off != 0 && width <= 0, sau đó hoạt động định vị không thành công. Mặt khác, nếu way != basic_ios::curhoặc off != 0và nếu thao tác cuối cùng là đầu ra, thì hãy cập nhật chuỗi đầu ra và ghi bất kỳ chuỗi không dịch chuyển nào. Tiếp theo, tìm đến vị trí mới: nếu width > 0, gọi fseek(file, width * off, whence), nếu không hãy gọi fseek(file, 0, whence).

fseekchấp nhận một longtham số. Nếu off_typestreamoffđược định nghĩa là long long(như được đề xuất bởi tiêu chuẩn), điều này có thể dẫn đến chuyển đổi xuống longkhi gọi fseek(file, width * off, whence)(dẫn đến khả năng khó chẩn đoán lỗi). Điều này đặt ra câu hỏi cho toàn bộ lý do để giới thiệu streamoffloại ở nơi đầu tiên.

Đây là cố ý hay một khiếm khuyết trong tiêu chuẩn?


8
khiếm khuyết trông như thế nào.
Yakk - Adam Nevraumont

Tôi nghĩ rằng tôi thấy rằng gcc libstdc ++ sử dụng fseeko64 .
KamilCuk

1
Offhand, nó không giống như seekoffnhất thiết phải sử dụng fseek dưới mui xe. Thay vào đó, hành vi (có lẽ quen thuộc?) fseekĐược sử dụng để giải thích những gì seekoffđang làm.
jjramsey

@jjramsey Đây cũng là ấn tượng của tôi. Tuy nhiên, cách nó được thực hiện dường như đề xuất một yêu cầu hơn là một lời giải thích.
jceed2

1
@jjramsey Tôi đồng ý rằng phần "Hiệu ứng" có thể được giải thích hợp lý có nghĩa là nó không thực sự phải gọi fseekmiễn là nó làm điều gì đó có cùng hiệu ứng. Nhưng fseekvới phần bù nhỏ hơn LONG_MINhoặc lớn hơn LONG_MAXkhông có tác dụng, do đó, lời giải thích ít nhất là không đầy đủ, ít nhất là cho các triển khai ở nơi streamoffrộng hơn long.
Keith Thompson

Câu trả lời:


6

Tôi nghĩ rằng kết luận mà bạn rút ra từ điều này, rằng có sự không phù hợp giữa các luồng C ++ và fseekđiều đó sẽ dẫn đến các lỗi thời gian chạy, là không chính xác. Tình hình có vẻ là:

  1. Trên các hệ thống có long64 bit, streamoffđược định nghĩa là longseekoffhàm gọi fseek.

  2. Trên các hệ thống có long32 bit nhưng HĐH hỗ trợ bù tệp 64 bit, streamoffđược định nghĩa long longseekoffgọi một hàm gọi là fseekohoặc fseeko64chấp nhận bù 64 bit.

Đây là đoạn trích từ định nghĩa seekofftrên hệ thống Linux của tôi:

#ifdef _GLIBCXX_USE_LFS
    if (!fseeko64(_M_file, __off, __whence))
      __ret = std::streampos(ftello64(_M_file));
#else
    if (!fseek(_M_file, __off, __whence))
      __ret = std::streampos(std::ftell(_M_file));
#endif

LFS là viết tắt của Hỗ trợ tệp lớn .

Kết luận: Trong khi tiêu chuẩn cho thấy một định nghĩa cho streamoffrằng mâu thuẫn bề ngoài với yêu cầu rằng seekoffinvoke fseek, nhà thiết kế thư viện hiểu rằng họ phải gọi biến thể của fseekchấp nhận đầy đủ các offsets rằng sự hỗ trợ hệ điều hành.


@ypnos Tôi không downvote và tôi thấy câu trả lời này hữu ích. Tôi đoán ai đó bị hạ thấp vì nó bỏ lỡ điểm. Vấn đề không phải là có những triển khai lành mạnh mà bỏ qua tiêu chuẩn về vấn đề này, vấn đề là tiêu chuẩn cần phải được bỏ qua để việc thực hiện được lành mạnh.
jceed2

6
The situation seems to be:- Tình hình là việc thực hiện không được phép không gọi fseektrong seekoff. Nó phải gọi fseek, nó không, tiêu chuẩn nói rằng nó phải. Tôi có thể lập luận rằng việc thực hiện này là không hợp lệ. Tôi tin rằng nó không trả lời câu hỏi. Och, tìm thấy llvm , nó gọi fseeko.
KamilCuk

Giống như một FYI, VC ++ gọi _fseeki64chức năng này; mà dường như cũng vi phạm những gì tiêu chuẩn nói.
ChrisMM

1
Đây là một trường hợp của những người thực hiện nhận ra vấn đề và bỏ qua các tiêu chuẩn. Tôi rất vui vì họ đã làm, nhưng tiêu chuẩn thực sự cần phải được sửa chữa.
NathanOliver

1
Một số người đang lấy tiêu chuẩn quá theo nghĩa đen. Nó không đòi hỏi việc thực hiện theo nghĩa đen gọi một hàm được gọi fseek. Ở nơi khác, tiêu chuẩn mô tả một cái gì đó là "như thể bằng cách gọi fseek(...)." Nếu nó quan tâm rất nhiều về việc gọi theo nghĩa đen fseek, tuyên bố đó sẽ khác. Nghiêm túc mà nói, bạn sẽ làm gì, nếu bạn đang thực hiện một thư viện C ++? Bạn có khăng khăng gọi fseekvới 32 bit thấp hơn của phần bù tệp 64 bit, bởi vì một tài liệu cho bạn biết? Khách hàng của bạn sẽ cảm ơn bạn vì điều đó?
Willis Blackburn
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.