Saya tahu ada standar di balik semua implementasi kompiler C, jadi seharusnya tidak ada fitur tersembunyi. Meskipun demikian, saya yakin semua pengembang C memiliki trik tersembunyi / rahasia yang mereka gunakan setiap saat.
c
hidden-features
bernardn
sumber
sumber
Jawaban:
Pointer fungsi. Anda dapat menggunakan tabel pointer fungsi untuk mengimplementasikan, misalnya, penerjemah kode tidak langsung cepat (FORTH) atau dispatcher kode byte, atau untuk mensimulasikan metode virtual mirip OO.
Kemudian ada permata tersembunyi di perpustakaan standar, seperti qsort (), bsearch (), strpbrk (), strcspn () [dua yang terakhir berguna untuk mengimplementasikan penggantian strtok ()].
Kesalahan C adalah bahwa aritmatika yang ditandatangani melimpah adalah perilaku tidak terdefinisi (UB). Jadi, setiap kali Anda melihat ekspresi seperti x + y, keduanya sedang ditandatangani, mungkin berpotensi meluap dan menyebabkan UB.
sumber
Lebih banyak trik dari kompiler GCC, tetapi Anda dapat memberikan petunjuk indikasi cabang ke kompiler (umum di kernel Linux)
lihat: http://kerneltrap.org/node/4705
Yang saya sukai tentang ini adalah ia juga menambahkan ekspresi pada beberapa fungsi.
sumber
Ini adalah item opsional dalam standar, tetapi harus merupakan fitur tersembunyi, karena orang-orang secara konstan mendefinisikannya. Satu basis kode yang telah saya kerjakan (dan masih dilakukan, untuk saat ini) memiliki beberapa definisi ulang, semua dengan pengidentifikasi yang berbeda. Sebagian besar waktu dengan makro preprosesor:
Dan seterusnya. Itu membuat saya ingin mencabut rambut saya. Cukup gunakan typedefs integer standar freaking!
sumber
Operator koma tidak banyak digunakan. Ini tentu saja dapat disalahgunakan, tetapi juga bisa sangat berguna. Penggunaan ini adalah yang paling umum:
Tetapi Anda dapat menggunakan operator ini di mana saja. Mengamati:
Setiap pernyataan dievaluasi, tetapi nilai ekspresi akan menjadi pernyataan terakhir yang dievaluasi.
sumber
menginisialisasi struktur ke nol
ini akan nol semua elemen struktur.
sumber
memset
/calloc
lakukan "semua byte nol" (yaitu nol fisik), yang memang tidak didefinisikan untuk semua jenis.{ 0 }
dijamin untuk mengintensifkan segalanya dengan nilai nol logis yang tepat . Pointer, misalnya, dijamin untuk mendapatkan nilai nol yang tepat, bahkan jika nilai nol pada platform yang diberikan adalah0xBAADFOOD
.memset
dilakukannya (dengan0
argumen kedua). Anda mendapatkan nol logis ketika Anda menginisialisasi / menetapkan0
(atau{ 0 }
) ke objek dalam kode sumber. Kedua jenis nol ini tidak serta merta menghasilkan hasil yang sama. Seperti pada contoh dengan pointer. Ketika Anda melakukannyamemset
pada pointer, Anda mendapatkan0x0000
pointer. Tetapi ketika Anda menetapkan0
ke pointer, Anda mendapatkan nilai pointer nol , yang mungkin pada tingkat fisik0xBAADF00D
atau apa pun.double
,. Biasanya ini diterapkan sesuai dengan standar IEEE-754, di mana nol logis dan nol fisik adalah sama. Tetapi IEEE-754 tidak diperlukan oleh bahasa. Jadi mungkin saja terjadi bahwa ketika Anda melakukannyadouble d = 0;
(nol logis), secara fisik beberapa bit dalam memori yang ditempatid
tidak akan menjadi nol.Konstanta multi-karakter:
Ini diatur
x
ke0x41424344
(atau0x44434241
, tergantung pada arsitektur).EDIT: Teknik ini tidak portabel, terutama jika Anda membuat serial int. Namun, dapat sangat berguna untuk membuat enum yang mendokumentasikan sendiri. misalnya
Ini membuatnya lebih sederhana jika Anda melihat dump memori mentah dan perlu menentukan nilai enum tanpa harus mencarinya.
sumber
Saya tidak pernah menggunakan bidang bit tetapi kedengarannya keren untuk hal-hal tingkat rendah.
Ini berarti bahwa
sizeof(cat)
bisa sekecilsizeof(char)
.Komentar yang dimasukkan oleh Aaron dan leppie , terima kasih kawan.
sumber
C memiliki standar tetapi tidak semua kompiler C sepenuhnya memenuhi syarat (Saya belum melihat kompiler C99 yang sepenuhnya patuh!).
Yang mengatakan, trik yang saya sukai adalah mereka yang tidak jelas dan portabel di seluruh platform karena mereka bergantung pada semantik C. Mereka biasanya tentang makro atau bit aritmatika.
Misalnya: bertukar dua bilangan bulat tanpa tanda tangan tanpa menggunakan variabel sementara:
atau "extending C" untuk mewakili mesin negara hingga seperti:
yang bisa dicapai dengan makro berikut:
Secara umum, saya tidak suka trik yang cerdik tetapi membuat kode tidak perlu rumit untuk dibaca (sebagai contoh swap) dan saya suka yang membuat kode lebih jelas dan langsung menyampaikan maksud (seperti contoh FSM) .
sumber
Struktur yang saling terkait seperti Perangkat Duff :
sumber
Saya sangat menyukai inisialisasi yang ditunjuk, ditambahkan dalam C99 (dan didukung dalam gcc untuk waktu yang lama):
Inisialisasi array tidak lagi tergantung posisi. Jika Anda mengubah nilai FOO atau BAR, inisialisasi array akan secara otomatis sesuai dengan nilai baru mereka.
sumber
C99 memiliki beberapa inisialisasi struktur pesanan mengagumkan.
sumber
struktur dan susunan anonim adalah yang favorit saya. (cf. http://www.run.montefiore.ulg.ac.be/~martin/resources/kung-f00.html )
atau
bahkan dapat digunakan untuk memulai daftar yang ditautkan ...
sumber
gcc memiliki sejumlah ekstensi ke bahasa C yang saya nikmati, yang dapat ditemukan di sini . Beberapa favorit saya adalah atribut fungsi . Salah satu contoh yang sangat berguna adalah atribut format. Ini dapat digunakan jika Anda mendefinisikan fungsi kustom yang mengambil string format printf. Jika Anda mengaktifkan atribut fungsi ini, gcc akan melakukan pemeriksaan pada argumen Anda untuk memastikan bahwa string format dan argumen Anda cocok dan akan menghasilkan peringatan atau kesalahan yang sesuai.
sumber
fitur (tersembunyi) yang "mengejutkan" saya ketika saya pertama kali melihat adalah tentang printf. fitur ini memungkinkan Anda untuk menggunakan variabel untuk memformat penentu format sendiri. mencari kode, Anda akan melihat lebih baik:
karakter * mencapai efek ini.
sumber
Yah ... Saya pikir salah satu poin kuat dari bahasa C adalah portabilitas dan standarnya, jadi setiap kali saya menemukan beberapa "trik tersembunyi" dalam implementasi yang saya gunakan saat ini, saya mencoba untuk tidak menggunakannya karena saya mencoba untuk menjaga saya Kode C sebagai standar dan portabel mungkin.
sumber
Menyusun pernyataan waktu, seperti yang sudah dibahas di sini .
sumber
Rangkaian string yang konstan
Saya cukup terkejut tidak melihat semuanya sudah ada di jawaban, karena semua kompiler saya tahu mendukungnya, tetapi banyak programmer tampaknya mengabaikannya. Terkadang ini sangat berguna dan tidak hanya saat menulis makro.
Gunakan case yang saya miliki di kode saya saat ini: Saya punya
#define PATH "/some/path/"
di file konfigurasi (benar-benar diselesaikan oleh makefile). Sekarang saya ingin membangun path lengkap termasuk nama file untuk membuka sumber daya. Ini hanya berlaku untuk:Alih-alih yang mengerikan, tetapi sangat umum:
Perhatikan bahwa solusi mengerikan yang umum adalah:
sumber
Yah, saya tidak pernah menggunakannya, dan saya tidak yakin apakah saya akan merekomendasikan hal ini kepada siapa pun, tetapi saya merasa pertanyaan ini tidak akan lengkap tanpa menyebutkan trik rutinitas Simon Tatham .
sumber
Saat menginisialisasi array atau enum, Anda dapat menempatkan koma setelah item terakhir dalam daftar penginisialisasi. misalnya:
Ini dilakukan agar jika Anda membuat kode secara otomatis, Anda tidak perlu khawatir menghilangkan koma terakhir.
sumber
Tugas struktur keren. Banyak orang tampaknya tidak menyadari bahwa struct adalah nilai juga, dan dapat ditetapkan, tidak perlu digunakan
memcpy()
, ketika tugas sederhana berhasil.Misalnya, pertimbangkan beberapa perpustakaan grafis 2D imajiner, mungkin menentukan jenis untuk mewakili koordinat layar (integer):
Sekarang, Anda melakukan hal-hal yang mungkin terlihat "salah", seperti menulis fungsi yang menciptakan titik yang diinisialisasi dari argumen fungsi, dan mengembalikannya, seperti:
Ini aman, selama (tentu saja) karena nilai kembali disalin oleh nilai menggunakan penugasan struct:
Dengan cara ini Anda dapat menulis kode yang cukup bersih dan berorientasi objek-ish, semuanya dalam standar sederhana C.
sumber
Pengindeksan vektor aneh:
sumber
Kompiler C mengimplementasikan salah satu dari beberapa standar. Namun, memiliki standar tidak berarti bahwa semua aspek bahasa didefinisikan. Perangkat Duff , misalnya, adalah fitur 'tersembunyi' favorit yang telah menjadi sangat populer sehingga kompiler modern memiliki kode pengenalan tujuan khusus untuk memastikan bahwa teknik optimasi tidak mengalahkan efek yang diinginkan dari pola yang sering digunakan ini.
Secara umum, fitur tersembunyi atau trik bahasa tidak disarankan saat Anda menggunakan pisau cukur yang menggunakan standar C apa pun yang digunakan kompiler Anda. Banyak trik semacam itu tidak bekerja dari satu kompiler ke yang lain, dan seringkali fitur-fitur semacam ini akan gagal dari satu versi suite kompiler oleh pabrikan yang diberikan ke versi lain.
Berbagai trik yang melanggar kode C meliputi:
Masalah dan masalah lain yang muncul setiap kali programmer membuat asumsi tentang model eksekusi yang semuanya ditentukan dalam sebagian besar standar C sebagai perilaku 'tergantung kompiler'.
sumber
Saat menggunakan sscanf Anda dapat menggunakan% n untuk mencari tahu di mana Anda harus terus membaca:
Tampaknya, Anda tidak dapat menambahkan jawaban lain, jadi saya akan memasukkan jawaban kedua di sini, Anda dapat menggunakan "&&" dan "||" sebagai persyaratan:
Kode ini akan menampilkan:
sumber
menggunakan INT (3) untuk mengatur break point pada kode adalah favorit saya sepanjang masa
sumber
Fitur "tersembunyi" favorit saya dari C, adalah penggunaan% n di printf untuk menulis kembali ke stack. Biasanya printf memunculkan nilai parameter dari stack berdasarkan string format, tetapi% n dapat menuliskannya kembali.
Lihat bagian 3.4.2 di sini . Dapat menyebabkan banyak kerentanan buruk.
sumber
Pengecekan asumsi waktu-kompilasi menggunakan enum: Contoh bodoh, tetapi bisa sangat berguna untuk perpustakaan dengan konstanta yang dapat dikonfigurasikan waktu kompilasi.
sumber
#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]
)Gcc (c) memiliki beberapa fitur menyenangkan yang dapat Anda aktifkan, seperti deklarasi fungsi bersarang, dan bentuk a?: B dari operator?:, Yang mengembalikan a jika a tidak salah.
sumber
Saya menemukan 0 bitfields baru-baru ini.
yang akan memberikan tata letak
bukannya tanpa: 0;
Bidang 0 width memberitahu bahwa bitfield berikut harus ditetapkan pada entitas atom berikutnya (
char
)sumber
Makro argumen variabel gaya C99, alias
yang akan digunakan seperti
Di sini saya juga menggunakan operator stringisasi dan string concatentation konstan, fitur lain yang sangat saya sukai.
sumber
Variabel ukuran variabel otomatis juga berguna dalam beberapa kasus. Ini ditambahkan i nC99 dan telah didukung dalam gcc untuk waktu yang lama.
Anda berakhir dengan buffer pada stack dengan ruang untuk header protokol ukuran tetap plus data ukuran variabel. Anda bisa mendapatkan efek yang sama dengan Alokasi (), tetapi sintaks ini lebih kompak.
Anda harus memastikan extraPadding adalah nilai yang masuk akal sebelum memanggil rutin ini, atau Anda akhirnya menumpuknya. Anda harus memeriksa argumen sebelum menelepon malloc atau teknik alokasi memori lainnya, jadi ini tidak biasa.
sumber