The acuan pelaksanaan CRC32 menghitung tabel lookup saat runtime:
/* Table of CRCs of all 8-bit messages. */
unsigned long crc_table[256];
/* Flag: has the table been computed? Initially false. */
int crc_table_computed = 0;
/* Make the table for a fast CRC. */
void make_crc_table(void)
{
unsigned long c;
int n, k;
for (n = 0; n < 256; n++) {
c = (unsigned long) n;
for (k = 0; k < 8; k++) {
if (c & 1) {
c = 0xedb88320L ^ (c >> 1);
} else {
c = c >> 1;
}
}
crc_table[n] = c;
}
crc_table_computed = 1;
}
Bisakah Anda menghitung tabel pada waktu kompilasi, sehingga menyingkirkan fungsi dan flag status?
code-challenge
c++
compile-time
fredoverflow
sumber
sumber
Jawaban:
Inilah solusi C sederhana:
crc32table.c
Itu bergantung pada
__COUNTER__
makro tidak standar , serta semantik evaluasi di mana__COUNTER__
dievaluasi sebelum diteruskan sebagai argumen ke makro.Perhatikan bahwa, sejak
STEP
mengevaluasi argumennya dua kali, danCRC
menggunakan delapan pemanggilan bersarang, ada ledakan kombinatorial kecil dalam ukuran kode:Saya menguji ini di GCC 4.6.0 dan Dentang 2.8 pada Linux 32-bit, dan keduanya menghasilkan tabel yang benar.
sumber
Lingkaran inti
dapat dikonversi menjadi fungsi-meta:
Kemudian, 256 panggilan ke fungsi-meta ini (untuk penginisialisasi array) dihasilkan oleh preprocessor:
Jika Anda telah memasang Boost, membuat penginisialisasi array sedikit lebih sederhana:
Akhirnya, driver tes berikut ini hanya mencetak semua elemen array ke konsol:
sumber
Solusi C ++ 0x
Bekerja pada GCC (4.6.1) dan Dentang (trunk 134121).
sumber
C >> 1
, Apakah tidak menggeser nilai negatif ke perilaku yang tidak ditentukan yang benar? ;)C
sebuahunsigned long
. Array konstan didefinisikan diinisialisasi oleh ekspansi paketD...
.D
adalah paket parameter template non-tipe. Setelah GCC mendukungnya, Anda juga dapat mendeklarasikan array di dalam kelasstatic unsigned long constexpr crc_table[] = { D... };
, tetapi GCC belum mem-parsing inisialisasi di kelas. Manfaatnya adalah bahwacompute<>::crc_table[I]
dapat digunakan dalam ekspresi konstan nanti dalam kode.C ++ 0x dengan
constexpr
. Bekerja pada GCC4.6.1Anda kemudian dapat menggunakan
crc_table.data[X]
pada waktu kompilasi karenacrc_table
iniconstexpr
.sumber
Ini adalah metaprogram pertama saya :
Saya "hardcoded" panggilan ke template yang melakukan perhitungan :)
sumber
times
templatunsigned crc_table[] = { f<0>::value , f<0 + 1>::value , f<0 + 2>::value , f<0 + 2 + 1>::value , f<0 + 4>::value , f<0 + 4 + 1>::value , f<0 + 4 + 2>::value , f<0 + 4 + 2 + 1>::value , f<0 + 8>::value ,
menggunakan preprocessor. Diperlukan waktu untuk mengkompilasi seperti milik saya. Jika mau, Anda dapat membaca paragraf terakhir sebagai "Saya membuka gulungan lingkaran luar". Tidak ada pilihan lain di C ++ 03D
Itu benar-benar membuat C ++ malu, bukan?
sumber
eval
.C / C ++,
306295 byteBekerja secara terbalik, kita berakhir dengan array panjang tanpa tanda bernama crc_table. Kita dapat menghilangkan ukuran array karena makro akan memastikan ada persis 256 elemen dalam array. Kami menginisialisasi array dengan 16 'baris' data dengan menggunakan 16 doa makro R.
Setiap doa R berkembang menjadi empat fragmen (makro F) dari empat konstanta (makro K) dengan total 16 'kolom' data.
Makro K adalah loop terbuka dengan diindeks oleh k dalam kode dari pertanyaan asli. Ini memperbarui nilai c delapan kali dengan memanggil makro C.
Solusi berbasis preprosesor ini menggunakan sedikit memori selama ekspansi makro. Saya mencoba membuatnya sedikit lebih pendek dengan memiliki level tambahan ekspansi makro dan compiler saya muntah. Kode di atas mengkompilasi (secara perlahan) dengan Visual C ++ 2012 dan g ++ 4.5.3 di bawah Cygwin (Windows 7 64 bit 8GB RAM).
Edit:
Fragmen di atas adalah 295 byte termasuk spasi. Setelah memperluas semua makro kecuali untuk C tumbuh menjadi 9,918 byte. Karena setiap tingkat makro C diperluas ukurannya tumbuh dengan cepat:
Jadi pada saat semua makro telah diperluas, file 295 byte kecil itu berkembang menjadi lebih dari 2,7 megabita kode yang harus dikompilasi untuk menghasilkan array 1024 byte asli (dengan asumsi 32 bit nilai panjang yang tidak ditandatangani)!
Suntingan lain:
Saya memodifikasi makro C berdasarkan makro dari jawaban lain untuk memeras tambahan 11 byte, dan sangat mengurangi ukuran makro yang diperluas penuh. Meskipun 2,7 MB tidak seburuk 54 MB (ukuran akhir sebelumnya dari semua ekspansi makro), ini masih signifikan.
sumber
Saya akan memodifikasi jawaban sebelumnya dengan mengganti tiga baris terakhir dengan:
Di mana crcByte adalah makro K tanpa koma tertinggal. Kemudian buat tabel itu sendiri dengan:
Dan jangan pernah meninggalkan ukuran array karena kompiler akan memverifikasi bahwa Anda memiliki jumlah elemen yang benar.
sumber