Saat ini saya sedang bekerja dengan sistem tertanam dan mencari cara untuk menerapkan string pada mikroprosesor tanpa sistem operasi. Sejauh ini apa yang saya lakukan hanya menggunakan ide untuk memiliki NULL diakhiri dengan pointer karakter dan memperlakukan mereka sebagai string di mana NULL menandakan akhir. Saya tahu ini cukup umum, tetapi bisakah Anda selalu mengandalkan ini?
Alasan saya bertanya adalah karena saya berpikir mungkin menggunakan sistem operasi waktu nyata, dan saya ingin menggunakan kembali sebanyak mungkin kode saya saat ini. Jadi untuk berbagai pilihan yang ada di luar sana, dapatkah saya berharap string bekerja dengan baik?
Biarkan saya lebih spesifik untuk kasus saya. Saya menerapkan sistem yang mengambil dan memproses perintah melalui port serial. Bisakah saya menjaga kode pemrosesan perintah saya sama, dan kemudian berharap bahwa objek string yang dibuat pada RTOS (yang berisi perintah) untuk semua akan dihentikan NULL? Atau, apakah akan berbeda berdasarkan OS?
Memperbarui
Setelah disarankan untuk melihat pertanyaan ini, saya telah menentukan bahwa itu tidak menjawab apa yang saya tanyakan. Pertanyaannya sendiri adalah menanyakan apakah panjang string harus selalu dilewati yang sama sekali berbeda dari apa yang saya tanyakan, dan meskipun beberapa jawaban memiliki informasi berguna di dalamnya, mereka tidak persis seperti yang saya cari. Jawaban di sana sepertinya memberikan alasan mengapa atau mengapa tidak mengakhiri string dengan karakter nol. Perbedaan dengan apa yang saya tanyakan adalah apakah saya dapat lebih atau kurang mengharapkan string bawaan dari platform yang berbeda untuk mengakhiri string mereka sendiri dengan nol, tanpa harus keluar dan mencoba setiap platform di luar sana jika itu masuk akal.
sumber
Jawaban:
Hal-hal yang disebut "string C" akan diakhiri null pada platform apa pun. Begitulah fungsi perpustakaan C standar menentukan akhir string.
Dalam bahasa C, tidak ada yang menghentikan Anda dari memiliki array karakter yang tidak berakhir dengan nol. Namun Anda harus menggunakan beberapa metode lain untuk menghindari kehabisan string.
sumber
char
array yang diakhiri null ,char
array dengan panjang yang disandikan dalam byte pertama (umumnya dikenal sebagai "string Pascal"),wchar_t
versi berbasis dari kedua di atas, danchar
array yang menggabungkan kedua metode: panjang dikodekan dalam byte pertama, dan karakter nol mengakhiri string.Penentuan karakter terminating tergantung pada kompiler untuk literal dan implementasi pustaka standar untuk string secara umum. Itu tidak ditentukan oleh sistem operasi.
Konvensi
NUL
penghentian kembali ke pra-standar C, dan dalam 30+ tahun, saya tidak bisa mengatakan saya mengalami lingkungan yang melakukan hal lain. Perilaku ini dikodifikasikan dalam C89 dan terus menjadi bagian dari standar bahasa C (tautan ke konsep C99):NUL
string-diminminasikan dengan mengharuskan agarNUL
ditambahkan ke string literal.Tidak ada alasan mengapa seseorang tidak dapat menulis fungsi yang menangani string yang diakhiri oleh beberapa karakter lain, tetapi juga tidak ada alasan untuk melawan standar yang ditetapkan dalam banyak kasus kecuali tujuan Anda adalah membuat programer cocok. :-)
sumber
printf("string: \"%s\"\n", "my cool string")
. Satu-satunya cara melewati empat parameter dalam kasus ini (selain beberapa jenis terminasi byte) adalah dengan mendefinisikan string menjadi sesuatu sepertistd::string
di C ++, yang memiliki masalah dan keterbatasannya sendiri.NUL
-minimalkan mereka tidak peduli apa pun: "Dalam fase terjemahan 7, byte atau kode dari nilai nol ditambahkan ke setiap urutan karakter multibyte yang dihasilkan dari string literal atau literal. " Fungsi perpustakaan menggunakan definisi 7.1.1 berhenti pada saat pertamaNUL
mereka menemukan dan tidak akan tahu atau peduli bahwa ada karakter tambahan di luarnya.Tidak ada tipe data string dalam bahasa C, tetapi ada string literal .
Jika Anda meletakkan string literal di program Anda, biasanya NUL akan dihentikan (tetapi lihat kasus khusus, dibahas dalam komentar di bawah ini.) Artinya, Jika Anda meletakkan
"foobar"
di tempat di manaconst char *
nilai diharapkan, kompiler akan memancarkanfoobar⊘
ke segmen const / kode / bagian dari program Anda, dan nilai ekspresi akan menjadi penunjuk ke alamat tempat ia menyimpanf
karakter. (Catatan: Saya menggunakan⊘
untuk menandakan byte NUL.)Satu-satunya pengertian lain di mana bahasa C memiliki string adalah, ia memiliki beberapa pustaka rutin standar yang beroperasi pada urutan karakter yang diakhiri NUL. Rutinitas pustaka tersebut tidak akan ada di lingkungan bare metal kecuali Anda porting sendiri.
Itu hanya kode --- tidak berbeda dengan kode yang Anda tulis sendiri. Jika Anda tidak merusaknya saat Anda porting, maka mereka akan melakukan apa yang selalu mereka lakukan (misalnya, berhenti pada NUL.)
sumber
char foo[4] = "abcd";
adalah cara yang valid untuk membuat array non-null-dihentikan empat karakter.char const *
ekspresi yang diharapkan. Saya lupa bahwa inisialisasi C terkadang dapat mematuhi aturan yang berbeda.char[4]
. Itu bukan string, tetapi ini diinisialisasi dari satustatic
ke contoh Ruakh, maka kompiler dapat memancarkan "abcd" non NUL ke segmen data yang diinisialisasi sehingga variabel diinisialisasi oleh pemuat program. Jadi, Ruakh benar: Setidaknya ada satu kasus di mana penampilan string literal dalam suatu program tidak mengharuskan kompiler untuk memancarkan string yang diakhiri NUL. (ps, saya benar-benar mengkompilasi contoh dengan gcc 5.4.0, dan kompiler tidak memancarkan NUL.)Seperti yang telah disebutkan orang lain, null terminating string adalah konvensi dari C Standard Library. Anda dapat menangani string dengan cara apa pun yang Anda inginkan jika Anda tidak akan menggunakan perpustakaan standar.
Ini berlaku untuk semua sistem operasi dengan kompiler 'C', dan juga, Anda dapat menulis program 'C' yang tidak berjalan di bawah sistem operasi yang benar seperti yang Anda sebutkan dalam pertanyaan Anda. Contohnya adalah pengontrol untuk printer ink jet yang saya rancang sekali. Dalam sistem tertanam, overhead memori sistem operasi mungkin tidak diperlukan.
Dalam situasi memori ketat, saya akan melihat karakteristik kompiler saya berhadapan dengan set instruksi prosesor, misalnya. Dalam aplikasi di mana string diproses banyak, mungkin diinginkan untuk menggunakan deskriptor seperti panjang string. Saya sedang memikirkan sebuah kasus di mana CPU sangat efisien dalam bekerja dengan offset pendek dan / atau offset relatif dengan register alamat.
Jadi mana yang lebih penting dalam aplikasi Anda: ukuran dan efisiensi kode, atau kompatibilitas dengan OS atau Perpustakaan? Pertimbangan lain mungkin pemeliharaan. Semakin jauh Anda menyimpang dari konvensi, semakin sulit bagi orang lain untuk mempertahankannya.
sumber
Orang lain telah membahas masalah bahwa dalam C, string sebagian besar adalah apa yang Anda dapatkan dari mereka. Tetapi tampaknya ada beberapa kebingungan dalam pertanyaan Anda tentang terminator itu sendiri, dan dari satu perspektif, ini bisa menjadi hal yang dikhawatirkan oleh seseorang di posisi Anda.
String C diakhiri null. Artinya, mereka diakhiri oleh karakter nol
NUL
,. Mereka tidak diakhiri oleh null pointerNULL
, yang merupakan jenis nilai yang sama sekali berbeda dengan tujuan yang sama sekali berbeda.NUL
dijamin memiliki nilai integer nol. Di dalam string, itu juga akan memiliki ukuran tipe karakter yang mendasarinya, yang biasanya akan menjadi 1.NULL
tidak dijamin memiliki tipe integer sama sekali.NULL
dimaksudkan untuk digunakan dalam konteks pointer, dan umumnya diharapkan memiliki tipe pointer, yang seharusnya tidak dikonversi ke karakter atau integer jika kompiler Anda bagus. Walaupun definisiNULL
melibatkan mesin terbang0
, itu tidak dijamin untuk benar-benar memiliki nilai [1], dan kecuali jika kompiler Anda mengimplementasikan konstanta sebagai satu karakter#define
(banyak yang tidak, karenaNULL
benar - benar tidak boleh bermakna dalam non-karakter). pointer konteks), karena itu kode yang diperluas tidak dijamin untuk benar-benar melibatkan nilai nol (meskipun membingungkan memang melibatkan mesin terbang nol).Jika
NULL
diketik, kemungkinan juga tidak akan memiliki ukuran 1 (atau ukuran karakter lain). Ini mungkin dapat menyebabkan masalah tambahan, meskipun konstanta karakter aktual tidak memiliki ukuran karakter baik sebagian besar.Sekarang kebanyakan orang akan melihat ini dan berpikir, "null pointer sebagai apa pun selain semua-nol-bit? Omong kosong" - tetapi asumsi seperti itu hanya aman pada platform umum seperti x86. Karena Anda secara eksplisit menyebutkan minat untuk menargetkan platform lain, Anda perlu mempertimbangkan masalah ini, karena Anda telah secara eksplisit memisahkan kode Anda dari asumsi tentang sifat hubungan antara pointer dan integer.
Oleh karena itu, sementara string C adalah null-dihentikan, mereka tidak diakhiri oleh
NULL
, tetapi olehNUL
(biasanya ditulis'\0'
). Kode yang secara eksplisit digunakanNULL
sebagai terminator string akan bekerja pada platform dengan struktur alamat langsung, dan bahkan akan dikompilasi dengan banyak kompiler, tetapi sama sekali tidak benar C.[1] nilai null pointer yang sebenarnya dimasukkan oleh kompiler ketika membaca
0
token dalam konteks di mana ia akan dikonversi ke tipe pointer. Ini bukan konversi dari bilangan bulat nilai 0, dan tidak dijamin untuk terus jika apa pun selain token0
itu sendiri digunakan, seperti nilai dinamis dari variabel; konversi juga tidak dapat dibalik, dan penunjuk nol tidak harus menghasilkan nilai 0 saat dikonversi ke integer.sumber
NUL
Dijamin memiliki nilai integer nol." -> C tidak mendefinisikanNUL
. Sebaliknya C mendefinisikan bahwa string memiliki chracter null akhir , byte dengan semua bit diatur ke 0.Saya telah menggunakan string dalam C, itu berarti karakter dengan terminasi nol disebut Strings.
Ini tidak akan memiliki masalah ketika Anda menggunakan di baremetal atau di sistem operasi apa pun seperti Windows, Linux, RTOS: (FreeRTO, OSE).
Dalam embedded null terminasi dunia sebenarnya membantu lebih banyak token karakter sebagai string.
Saya telah menggunakan string dalam C seperti itu di banyak sistem kritis keselamatan.
Anda mungkin bertanya-tanya, apa sebenarnya string dalam C?
String C-style, yang merupakan array, ada juga string literal, seperti "ini". Pada kenyataannya, kedua tipe string ini hanyalah kumpulan karakter yang duduk bersebelahan dalam memori.
Misalnya, Anda dapat mendeklarasikan dan mendefinisikan array karakter, dan menginisialisasi dengan konstanta string:
Jawaban langsung: Anda tidak benar-benar perlu khawatir tentang penggunaan karakter dengan penghentian nol, karya ini terlepas dari platform apa pun.
sumber
NUL
secara otomatis ditambahkan.Seperti yang dikatakan orang lain, terminasi nol cukup universal untuk standar C. Tetapi (seperti yang juga ditunjukkan orang lain) tidak 100%. Sebagai contoh (lain), sistem operasi VMS biasanya menggunakan apa yang disebutnya "deskriptor string" http://h41379.www4.hpe.com/commercial/c/docs/5492p012.html diakses di C oleh #include <descrip.h >
Hal-hal tingkat aplikasi dapat menggunakan terminasi nol atau tidak, namun pengembang menganggapnya sesuai. Tetapi hal-hal VMS tingkat rendah benar-benar membutuhkan deskriptor, yang tidak menggunakan terminasi nol sama sekali (lihat tautan di atas untuk perincian). Ini sebagian besar agar semua bahasa (C, assembly, dll) yang secara langsung menggunakan VMS internal dapat memiliki antarmuka yang sama dengannya.
Jadi, jika Anda mengantisipasi segala jenis situasi serupa, Anda mungkin ingin lebih berhati-hati daripada yang mungkin disarankan "penghentian nol universal". Saya akan lebih berhati-hati jika saya melakukan apa yang Anda lakukan, tetapi untuk hal-hal tingkat aplikasi saya aman untuk menganggap pengakhiran nol. Saya tidak akan menyarankan tingkat keamanan yang sama untuk Anda. Kode Anda mungkin harus berinteraksi dengan assembly, dan / atau lainnya, kode bahasa di beberapa titik di masa depan, yang mungkin tidak selalu sesuai dengan standar C dari string yang diakhiri dengan null.
sumber
Dalam pengalaman saya tentang embedded, safety kritis dan sistem waktu nyata, tidak jarang menggunakan konvensi string C dan PASCAL, yaitu untuk memasok panjang string sebagai karakter pertama, (yang membatasi panjang hingga 255), dan untuk mengakhiri string dengan setidaknya satu 0x00, (
NUL
), yang mengurangi ukuran yang dapat digunakan menjadi 254.Salah satu alasannya adalah untuk mengetahui berapa banyak data yang Anda harapkan setelah byte pertama diterima dan yang lain adalah bahwa, dalam sistem seperti itu, ukuran buffer dinamis dihindari jika memungkinkan - mengalokasikan 256 ukuran buffer tetap lebih cepat dan lebih aman, (tidak ada perlu memeriksa jika
malloc
gagal). Lain adalah bahwa sistem lain yang berkomunikasi dengan Anda mungkin tidak ditulis dalam ANSI-C.Dalam setiap pekerjaan tertanam, penting untuk membuat dan memelihara Dokumen Kontrol Antarmuka (IDC), yang mendefinisikan semua struktur komunikasi Anda termasuk format string, endianness, ukuran integer, dll., Sesegera mungkin, ( idealnya sebelum memulai ), dan itu harus Anda, dan semua tim, kitab suci ketika menulis sistem - jika seseorang ingin memperkenalkan struktur atau format baru itu harus didokumentasikan di sana terlebih dahulu dan semua orang yang mungkin terkena informasi, mungkin dengan opsi untuk memveto perubahan .
sumber