Lampiran K ialah nama teknikal. Kata kunci biasa lain ialah __STDC_LIB_EXT1__ dan __STDC_WANT_LIB_EXT1__. Lampiran K mentakrifkan perkara akhiran _s "selamat" seperti sprintf_s() dan scanf_s().
Juga lihat pengalaman Lapangan dengan Lampiran K (2015) dan pemeriksaan Bounds - dokumentasi teknikal cppreference.com.
Apakah gunanya fungsi _s()? Mereka menyemak hujah mereka untuk lebih banyak invarian seperti "akan memanggil pengendali kekangan jika strim adalah batal, rentetan adalah batal, bufsz adalah sifar, atau penimbal akan menulis di luar sempadan melebihi panjang yang ditentukan". Itu nampaknya idea yang bagus, bukan? Yeah! Memang betul!
Intinya ialah anda boleh/boleh melakukan ini:
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> int main() { printf_s("Hello %s!\n", "Alan Turing"); return 0; }
Bagaimanakah itu dibandingkan dengan cara biasa melakukan sesuatu tanpa __STDC_WANT_LIB_EXT1__?
Selamat jalan
FILE *file = fopen("hello.txt", "r"); // file is OK.
FILE *file; errno_t err = fopen_s(&file, "hello.txt", "r"); // file is OK
Laluan yang menyedihkan
FILE *file = fopen("notexist.txt", "r"); // file is NULL, errno is set.
FILE *file; errno_t err = fopen_s(&file, "notexist.txt", "r"); // file is NULL, err is set.
Laluan buruk
FILE *file = fopen(NULL, NULL); // idk.
FILE *file; errno_t err = fopen_s(&file, NULL, NULL); // Constraint violated. Abort with message.
Ya, anda boleh menyesuaikan pengendali kekangan untuk hanya log masuk ke fail dan meneruskan seolah-olah tiada apa yang berlaku.
set_constraint_handler_s(ignore_handler_s); set_constraint_handler_s(abort_handler_s); set_constraint_handler_s(my_awesome_handler);
Perhatikan bagaimana fopen() normal mempunyai nilai pulangan yang sama (mungkin errno berbeza) untuk menunjukkan tahap keburukan ralat yang berbeza? Itulah yang cuba diperbaiki oleh fopen_s() ini. Sekurang-kurangnya, itulah bacaan saya. Saya menganggapnya seperti panik Rust!() vs Result
char* gets( char* str ); // (removed in C11) char* gets_s( char* str, rsize_t n ); // (since C11, annex K)Salin selepas log masukMembaca stdin ke dalam tatasusunan aksara yang ditunjuk oleh str sehingga aksara baris baharu ditemui atau fail akhir berlaku. Aksara null ditulis sejurus selepas aksara terakhir dibaca ke dalam tatasusunan. Aksara baris baharu dibuang tetapi tidak disimpan dalam penimbal.
Fungsi gets() tidak melakukan semakan sempadan, oleh itu fungsi ini sangat terdedah kepada serangan buffer-overflow. Ia tidak boleh digunakan dengan selamat (melainkan program berjalan dalam persekitaran yang menyekat perkara yang boleh muncul pada stdin). Atas sebab ini, fungsi tersebut telah ditamatkan dalam korigendum ketiga kepada standard C99 dan dialih keluar sama sekali dalam standard C11. fgets() dan gets_s() ialah penggantian yang disyorkan.
AMARAN: Jangan sesekali gunakan gets().
// BAD char buffer[1000]; gets(buffer); // ⚠️ Could write >1000 chars to `buffer`!
// GOOD char buffer[1000]; gets_s(buffer, sizeof(buffer)); // This will stop at 1000 chars.
Fungsi _s() nampaknya bagus untuk menghentikan tempat biasa di mana limpahan penimbal boleh berlaku.
Ia tidak dilaksanakan di mana-mana sahaja. Fungsi _s() ialah sambungan yang tidak tersedia dalam pelaksanaan libc seperti glibc GNU. Terdapat isu kecil lain seperti ia tidak ergonomik untuk multithreading dan kesilapan biasa untuk melakukan sizeof(src) dan bukannya sizeof(dest) untuk perkara seperti strcpy_s(), tetapi itu semua tidak bermakna jika dibandingkan dengan masalah ketersediaan.
Kebanyakan maklumat dalam talian yang saya temui nampaknya menunjukkan bahawa MSVC ialah satu-satunya pengkompil/libc utama yang telah melaksanakan Lampiran K.
Memandangkan fungsi _s() mewah ini tidak terdapat di mana-mana yang perlu dihimpunkan oleh kod anda, anda perlu menulis kod seperti ini:
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> int main() { printf_s("Hello %s!\n", "Alan Turing"); return 0; }
...untuk setiap contoh yang anda mahu lakukan strlen_s() atau fopen_s() atau strcpy_s(). Itulah cara yang baik untuk menjadi gila.
Jadi jelas sekali anda tidak akan menulis kod yang bergantung pada platform hanya untuk melakukan printf() asas dan strcpy() tetapi bagaimana pula dengan membungkus semua #ifdef __STDC_LIB_EXT1__ #barang lain dalam perpustakaan?
Terdapat dua perpustakaan yang kelihatan menjanjikan yang saya temui melalui carian Google pantas:
Jadi... jika anda mahu (atau dikehendaki oleh perkara keselamatan) menggunakan fungsi _s() tetapi juga tidak mahu mengehadkan diri anda kepada MSVC sahaja maka anda boleh menggunakan salah satu daripada ☝ perpustakaan tersebut.
? Untuk membaca lebih lanjut, lihat Pengalaman Lapangan dengan Lampiran K (2015) dan pemeriksaan Bounds - dokumentasi teknikal cppreference.com.
Atas ialah kandungan terperinci TIL CAnnex K wujud tetapi anda tidak sepatutnya menggunakannya. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!