Apakah ada cara untuk menggunakan sizeof
makro preprocessor?
Misalnya, ada banyak sekali situasi selama bertahun-tahun di mana saya ingin melakukan sesuatu seperti:
#if sizeof(someThing) != PAGE_SIZE
#error Data structure doesn't match page size
#endif
Hal persis yang saya periksa di sini benar-benar dibuat-buat - intinya adalah, saya sering suka memasukkan jenis (ukuran atau keselarasan) pemeriksaan waktu kompilasi ini untuk mencegah seseorang memodifikasi struktur data yang dapat tidak sejajar atau ukuran hal-hal yang akan menghancurkan mereka.
Tak perlu dikatakan - sepertinya saya tidak dapat menggunakan a sizeof
dengan cara yang dijelaskan di atas.
Jawaban:
Ada beberapa cara untuk melakukan ini. Cuplikan berikut tidak akan menghasilkan kode jika
sizeof(someThing)
sama denganPAGE_SIZE
; jika tidak, mereka akan menghasilkan kesalahan waktu kompilasi.1. C11 cara
Dimulai dengan C11, Anda dapat menggunakan
static_assert
(membutuhkan#include <assert.h>
).Pemakaian:
2. Makro khusus
Jika Anda hanya ingin mendapatkan kesalahan waktu kompilasi ketika
sizeof(something)
tidak seperti yang Anda harapkan, Anda dapat menggunakan makro berikut:Pemakaian:
Artikel ini menjelaskan secara detail mengapa ini berhasil.
3. Khusus MS
Pada kompiler Microsoft C ++ Anda dapat menggunakan makro C_ASSERT (memerlukan
#include <windows.h>
), yang menggunakan trik yang mirip dengan yang dijelaskan di bagian 2.Pemakaian:
sumber
gcc
(diuji pada versi 4.8.4) (Linux). Saat((void)sizeof(...
itu kesalahan denganexpected identifier or '(' before 'void'
danexpected ')' before 'sizeof'
. Tapi pada prinsipnyasize_t x = (sizeof(...
malah bekerja sebagaimana mestinya. Anda harus "menggunakan" hasilnya. Untuk memungkinkan ini dipanggil beberapa kali baik di dalam fungsi atau di lingkup global, sesuatu seperti ituextern char _BUILD_BUG_ON_ [ (sizeof(...) ];
dapat digunakan berulang kali (tanpa efek samping, sebenarnya tidak merujuk ke_BUILD_BUG_ON_
mana pun).Tidak. Petunjuk bersyarat mengambil serangkaian ekspresi bersyarat yang terbatas;
sizeof
adalah salah satu hal yang dilarang.Arahan preprocessing dievaluasi sebelum sumber diurai (setidaknya secara konseptual), jadi tidak ada jenis atau variabel apa pun untuk mendapatkan ukurannya.
Namun, ada beberapa teknik untuk mendapatkan pernyataan waktu kompilasi dalam C (misalnya, lihat halaman ini ).
sumber
Saya tahu ini jawaban yang terlambat, tetapi untuk menambahkan versi Mike, berikut adalah versi yang kami gunakan yang tidak mengalokasikan memori apa pun. Saya tidak menemukan cek ukuran asli, saya menemukannya di internet bertahun-tahun yang lalu dan sayangnya tidak dapat merujuk penulisnya. Dua lainnya hanyalah perluasan dari ide yang sama.
Karena mereka typedef's, tidak ada yang dialokasikan. Dengan __LINE__ di namanya, nama itu selalu berbeda sehingga dapat disalin dan ditempel jika diperlukan. Ini bekerja di kompiler MS Visual Studio C, dan kompiler GCC Arm. Ini tidak bekerja di CodeWarrior, CW mengeluh tentang redefinisi, tidak menggunakan konstruksi preprocessor __LINE__.
sumber
#define STATIC_ASSERT(condition) typedef char p__LINE__[ (condition) ? 1 : -1];
Saya tahu utas ini sangat tua tetapi ...
Solusi saya:
Selama ekspresi itu sama dengan nol, itu dikompilasi dengan baik. Ada lagi dan akan meledak di sana. Karena variabel di luar itu tidak akan memakan ruang, dan selama tidak ada yang mereferensikannya (yang tidak mereka lakukan) itu tidak akan menyebabkan kesalahan tautan.
Tidak sefleksibel makro pernyataan, tetapi saya tidak bisa membuatnya dikompilasi di versi GCC saya dan ini akan ... dan saya pikir itu akan dikompilasi di mana saja.
sumber
Jawaban yang ada hanya menunjukkan bagaimana mencapai efek "pernyataan waktu kompilasi" berdasarkan ukuran tipe. Itu mungkin memenuhi kebutuhan OP dalam kasus khusus ini, tetapi ada kasus lain di mana Anda benar-benar membutuhkan praprosesor bersyarat berdasarkan ukuran suatu tipe. Berikut cara melakukannya:
Tulis sendiri program C kecil seperti:
Kompilasi itu. Tulis skrip dalam bahasa skrip favorit Anda, yang menjalankan program C di atas dan menangkap hasilnya. Gunakan output tersebut untuk menghasilkan file header C. Misalnya, jika Anda menggunakan Ruby, akan terlihat seperti ini:
Kemudian tambahkan aturan ke Makefile Anda atau skrip build lainnya, yang akan membuatnya menjalankan skrip di atas untuk membangun
sizes.h
.Sertakan di
sizes.h
mana pun Anda perlu menggunakan praprosesor bersyarat berdasarkan ukuran.Selesai!
(Pernahkah Anda mengetik
./configure && make
untuk membangun program?configure
Skrip apa yang pada dasarnya sama seperti di atas ...)sumber
Bagaimana dengan makro berikutnya:
Misalnya dalam komentar MSVC mengatakan sesuatu seperti:
sumber
#if
arahan preprocessor.Sekadar referensi untuk pembahasan kali ini, saya melaporkan bahwa beberapa compiler mendapatkan sizeof () ar waktu pra-prosesor.
Jawaban JamesMcNellis benar, tetapi beberapa kompiler melewati batasan ini (ini mungkin melanggar ansi c ketat).
Untuk kasus ini, saya merujuk ke IAR C-compiler (mungkin yang terkemuka untuk mikrokontroler profesional / pemrograman tertanam).
sumber
sizeof
pada waktu praproses.sizeof
harus diperlakukan hanya sebagai pengenal.#if (sizeof(int) == 8)
benar - benar bekerja (pada beberapa kompiler)." Tanggapan: "Pasti sebelum waktu saya.", Berasal dari Dennis Ritchie.#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x))
mungkin berhasilsumber
#define SIZEOF_TYPE(x) (((x*)0) + 1)
#if
kondisi. Ini tidak memberikan keuntungan lebihsizeof(x)
.Dalam C11
_Static_assert
kata kunci ditambahkan. Ini bisa digunakan seperti:sumber
Dalam kode c ++ portabel saya ( http://www.starmessagesoftware.com/cpcclibrary/ ) ingin memberi perlindungan yang aman pada ukuran beberapa struct atau kelas saya.
Alih-alih menemukan cara bagi preprocessor untuk melakukan kesalahan (yang tidak dapat bekerja dengan sizeof () seperti yang dinyatakan di sini), saya menemukan solusi di sini yang menyebabkan kompiler melakukan kesalahan. http://www.barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
Saya harus menyesuaikan kode itu untuk membuatnya membuat kesalahan pada kompiler saya (xcode):
sumber
Setelah mencoba makro yang disebutkan, fragmen ini tampaknya menghasilkan hasil yang diinginkan (
t.h
):Berjalan
cc -E t.h
:Berjalan
cc -o t.o t.h
:42 bukanlah jawaban untuk segalanya ...
sumber
Untuk memeriksa pada waktu kompilasi ukuran struktur data terhadap batasannya, saya telah menggunakan trik ini.
Jika ukuran x lebih besar atau sama dari batasnya MAX_SIZEOF_X, maka gcc akan mengeluh dengan kesalahan 'ukuran larik terlalu besar'. VC ++ akan mengeluarkan kesalahan C2148 ('ukuran total larik tidak boleh melebihi 0x7fffffff byte') atau C4266 'tidak dapat mengalokasikan larik dengan ukuran konstan 0'.
Kedua definisi tersebut dibutuhkan karena gcc akan memungkinkan array berukuran nol untuk didefinisikan dengan cara ini (sizeof x - n).
sumber
The
sizeof
Operator tidak tersedia untuk preprocessor, tetapi Anda dapat mentransfersizeof
ke compiler dan memeriksa kondisi di runtime:sumber
compiler_size
? Apa yang coba ditunjukkan oleh teladan Anda?