Mengapa file standar C ++ menangani mencari seperti itu?

17

C ++ menggunakan streamofftipe untuk mewakili offset dalam aliran (file) dan didefinisikan sebagai berikut di [stream.types]:

using streamoff = implementation-defined ;

Jenis aliran adalah sinonim untuk salah satu tipe integral dasar yang ditandatangani dari ukuran yang cukup untuk mewakili ukuran file maksimum yang mungkin untuk sistem operasi. 287)

287) Biasanya panjang.

Ini masuk akal karena memungkinkan untuk mencari di dalam file besar (tidak seperti menggunakan long, yang mungkin hanya 32 bit lebar).

[filebuf.virtuals] mendefinisikan basic_filebuffungsi untuk mencari di dalam file sebagai berikut:

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

off_typesetara dengan streamoff, lihat [iostreams.limits.pos]. Namun, standar kemudian menjelaskan efek fungsi. Saya kesal dengan kalimat terakhir, yang membutuhkan panggilan ke fseek:

Efek : Biarkan widthdilambangkan a_codecvt.encoding(). Jika is_open() == false, atau off != 0 && width <= 0, maka operasi penentuan posisi gagal. Jika tidak, jika way != basic_ios::curatau off != 0, dan jika operasi terakhir adalah output, maka perbarui urutan output dan tuliskan urutan unshift. Selanjutnya, cari ke posisi baru: jika width > 0, panggilan fseek(file, width * off, whence), atau panggilan fseek(file, 0, whence).

fseekmenerima longparameter. Jika off_typedan streamoffdidefinisikan sebagai long long(seperti yang disarankan oleh standar), ini dapat menyebabkan konversi turun ke longsaat menelepon fseek(file, width * off, whence)(mengarah ke kemungkinan sulit mendiagnosis bug). Ini mempertanyakan seluruh alasan untuk memperkenalkan streamoffjenis di tempat pertama.

Apakah ini disengaja atau cacat dalam standar?

lanjutkan2
sumber
8
cacat seperti.
Yakk - Adam Nevraumont
Saya rasa saya melihat bahwa gcc libstdc ++ menggunakan fseeko64 .
KamilCuk
1
Begitu saja, sepertinya tidak seekoffperlu digunakan di fseek bawah tenda. Sebaliknya, perilaku (mungkin akrab?) fseekDigunakan untuk menjelaskan apa yang seekoffsedang dilakukan.
jjramsey
@ jjramsey Ini juga kesan saya. Namun, cara itu diungkapkan tampaknya menyarankan persyaratan daripada penjelasan.
jceed2
1
@ jjramsey Saya setuju bahwa bagian "Efek" secara wajar dapat diartikan bahwa itu tidak benar-benar harus memanggil fseekselama ia melakukan sesuatu dengan efek yang sama. Tetapi fseekdengan offset kurang dari LONG_MINatau lebih besar dari LONG_MAXtidak memiliki efek, sehingga penjelasannya paling tidak lengkap, setidaknya untuk implementasi di mana streamofflebih luas dari long.
Keith Thompson

Jawaban:

6

Saya pikir kesimpulan bahwa Anda menggambar dari ini, bahwa ada ketidakcocokan antara aliran C ++ dan fseekyang akan menyebabkan bug runtime, tidak benar. Situasinya tampaknya:

  1. Pada sistem di mana long64 bit, streamoffdidefinisikan sebagai long, dan seekofffungsinya memanggilfseek .

  2. Pada sistem di mana long32 bit tetapi OS mendukung offset file 64-bit, streamoffdidefinisikan sebagai long longdan seekoffmemanggil fungsi yang disebut salah satu fseekoatau fseeko64yang menerima offset 64-bit.

Berikut cuplikan dari definisi seekoffpada sistem Linux saya:

#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 adalah singkatan Large File Support .

Kesimpulan: Sementara standar menunjukkan definisi untuk streamoffyang konflik seolah-olah dengan persyaratan bahwa seekoffInvoke fseek, desainer perpustakaan memahami bahwa mereka harus memanggil varian fseekyang menerima berbagai macam offset yang mendukung OS.

Willis Blackburn
sumber
@ypnos Saya tidak downvote dan saya menemukan jawaban ini berguna. Saya kira seseorang downvoted karena tidak tepat sasaran. Masalahnya bukan bahwa ada implementasi waras yang mengabaikan standar dalam hal ini, masalahnya adalah bahwa standar perlu diabaikan agar implementasi menjadi waras.
Lanjutkan2
6
The situation seems to be:- Situasi adalah bahwa pelaksanaannya tidak diperbolehkan untuk tidak memanggil fseekdi seekoff. Itu harus memanggil fseek, tidak, standar mengatakan itu harus. Saya bisa berpendapat bahwa implementasi ini tidak valid. Saya percaya itu tidak menjawab pertanyaan. Och, ditemukan llvm , ia memanggil fseeko.
KamilCuk
Sama seperti FYI, VC ++ memanggil _fseeki64fungsi ini; yang juga tampaknya melanggar apa yang dikatakan standar.
ChrisMM
1
Ini adalah kasus pelaksana yang menyadari masalah dan mengabaikan standar. Saya senang mereka melakukannya, tetapi standarnya benar-benar perlu diperbaiki.
NathanOliver
1
Beberapa orang mengambil standar terlalu harfiah. Tidak menuntut bahwa implementasi secara harfiah memanggil fungsi yang disebut fseek. Di tempat lain standar menggambarkan sesuatu sebagai "seolah-olah dengan menelepon fseek(...)." Jika itu sangat peduli tentang panggilan secara harfiah fseek, pernyataan itu akan berbeda. Serius, apa yang akan Anda lakukan, jika Anda menerapkan pustaka C ++? Apakah Anda bersikeras untuk memanggil fseekdengan 32 bit yang lebih rendah dari offset file 64-bit, karena sebuah dokumen memberitahu Anda untuk melakukannya? Apakah pelanggan Anda akan berterima kasih untuk itu?
Willis Blackburn