Mengindentasi #defines

99

Saya tahu bahwa #defines, dll. Biasanya tidak pernah menjorok ke dalam. Mengapa?

Saya sedang mengerjakan beberapa kode saat ini yang memiliki campuran mengerikan #defines, #ifdefs, #elses, #endifs, dll. Semua ini sering tercampur dengan kode C normal. Huruf yang tidak menjorok ke #definedalam membuat mereka sulit dibaca. Dan campuran kode indentasi dengan non-indentasi #defineadalah mimpi buruk.

Apa manfaat tidak membuat indentasi #define? Apakah saya menjadi orang jahat jika saya membuat indentasi? Bukankah ini jauh lebih bagus?

#ifdef SDCC
    #if DEBUGGING == 1
        #if defined (pic18f2480)
            #define FLASH_MEMORY_END 0x3DC0
        #elif defined (pic18f2580)
            #define FLASH_MEMORY_END 0x7DC0
        #else
            #error "Can't set  up flash memory end!"
        #endif
    #else
        #if defined (pic18f2480)
            #define FLASH_MEMORY_END 0x4000
        #elif defined (pic18f2580)
            #define FLASH_MEMORY_END 0x8000
        #else
            #error "Can't set  up flash memory end!"
        #endif
    #endif
#else
    #if DEBUGGING == 1
        #define FLASH_MEMORY_END 0x7DC0
    #else
        #define FLASH_MEMORY_END 0x8000
    #endif
#endif
Magnet roket
sumber

Jawaban:

103

Praprosesor C pra-ANSI tidak mengizinkan spasi antara awal baris dan karakter "#"; awalan "#" harus selalu ditempatkan di kolom pertama.

Compiler C pra-ANSI tidak ada saat ini. Gunakan gaya mana pun (spasi sebelum "#" atau spasi antara "#" dan pengenal) yang Anda inginkan.

http://www.delorie.com/gnu/docs/gcc/cpp_48.html


sumber
26

Seperti yang telah dikatakan beberapa orang, beberapa kompiler Pra-ANSI memerlukan # untuk menjadi karakter pertama pada saluran tetapi mereka tidak memerlukan direktif de preprocessor untuk dilampirkan, jadi indentasi dibuat dengan cara ini.

#ifdef SDCC
#  if DEBUGGING == 1
#    if defined (pic18f2480)
#      define FLASH_MEMORY_END 0x3DC0
#    elif defined (pic18f2580)
#      define FLASH_MEMORY_END 0x7DC0
#    else
#      error "Can't set  up flash memory end!"
#    endif
#  else
#    if defined (pic18f2480)
#      define FLASH_MEMORY_END 0x4000
#    elif defined (pic18f2580)
#      define FLASH_MEMORY_END 0x8000
#    else
#      error "Can't set  up flash memory end!"
#    endif
#  endif
#else
#  if DEBUGGING == 1
#    define FLASH_MEMORY_END 0x7DC0
#  else
#    define FLASH_MEMORY_END 0x8000
#  endif
#endif

Saya sering melihat gaya ini di header Unix lama tetapi saya membencinya karena pewarnaan sintaks sering gagal pada kode tersebut. Saya menggunakan warna yang sangat terlihat untuk arahan pra-prosesor sehingga mereka menonjol (mereka berada di tingkat meta jadi tidak boleh menjadi bagian dari aliran kode normal). Anda bahkan dapat melihat bahwa SO tidak mewarnai urutan dengan cara yang berguna.

Patrick Schlüter
sumber
16

Mengenai parsing arahan preprocessor, standar C99 (dan standar C89 sebelumnya) sudah jelas tentang urutan operasi yang dilakukan secara logis oleh compiler. Secara khusus, saya percaya itu berarti kode ini:

/* */ # /* */ include /* */ <stdio.h> /* */

setara dengan:

#include <stdio.h>

Baik atau buruk, GCC 3.4.4 dengan '-std = c89 -pedantic' menerima baris sarat komentar, dengan cara apa pun. Saya tidak menganjurkan itu sebagai gaya - tidak sedetik pun (itu mengerikan). Saya hanya berpikir bahwa itu mungkin.

ISO / IEC 9899: 1999 bagian 5.1.1.2 Fase penerjemahan mengatakan:

  1. [Pemetaan karakter, termasuk trigraf]

  2. [Line splicing - menghapus garis miring terbalik baris baru]

  3. File sumber diuraikan menjadi token pra-pemrosesan dan urutan karakter spasi (termasuk komentar). File sumber tidak boleh diakhiri dengan sebagian token praproses atau dalam komentar sebagian. Setiap komentar diganti dengan satu karakter spasi. Karakter baris baru dipertahankan. Apakah setiap urutan karakter spasi kosong selain baris baru dipertahankan atau diganti dengan satu karakter spasi adalah definisi implementasi.

  4. Perintah praproses dijalankan, pemanggilan makro diperluas, [...]

Bagian 6.10 Arahan praproses mengatakan:

Arahan preprocessing terdiri dari urutan token preprocessing yang dimulai dengan # token preprocessing yang (pada awal fase terjemahan 4) adalah karakter pertama dalam file sumber (opsional setelah spasi yang tidak berisi karakter baris baru) atau yang mengikuti spasi kosong yang berisi setidaknya satu karakter baris baru, dan diakhiri dengan karakter baris baru berikutnya.

Satu-satunya sengketa yang mungkin adalah ekspresi tanda kurung '(pada awal terjemahan fase 4)', yang dapat berarti bahwa komentar sebelum hash harus tidak ada karena tidak akan digantikan oleh spasi hingga akhir fase 4.

Seperti yang telah dicatat orang lain, praprosesor C pra-standar tidak berperilaku seragam dalam beberapa cara, dan spasi sebelum dan dalam arahan praprosesor adalah salah satu area di mana penyusun yang berbeda melakukan hal yang berbeda, termasuk tidak mengenali arahan praprosesor dengan spasi di depannya. .

Patut dicatat bahwa penghapusan garis miring terbalik-baris baru terjadi sebelum komentar dianalisis. Karenanya, Anda tidak boleh mengakhiri //komentar dengan garis miring terbalik.

Jonathan Leffler
sumber
7

Saya tidak tahu mengapa itu tidak lebih umum. Ada kalanya saya suka memasukkan arahan preprocessor.

Satu hal yang terus menghalangi saya (dan terkadang meyakinkan saya untuk berhenti mencoba) adalah bahwa banyak atau sebagian besar editor / IDE akan melemparkan arahan ke kolom 1 dengan sedikit provokasi. Yang menyebalkan sekali.

Michael Burr
sumber
5

Hari-hari ini saya percaya ini terutama adalah pilihan gaya. Saya pikir pada satu titik di masa lalu, tidak semua kompiler mendukung gagasan mendefinisikan preprocessor indentasi. Saya melakukan beberapa penelitian dan tidak dapat mendukung pernyataan itu. Tetapi bagaimanapun, tampaknya semua kompiler modern mendukung gagasan indentasi makro pra-prosesor. Saya tidak memiliki salinan standar C atau C ++ jadi saya tidak tahu apakah ini perilaku standar atau tidak.

Seperti apakah itu gaya yang bagus atau tidak. Secara pribadi, saya menyukai gagasan untuk membiarkan semuanya tetap di kiri. Ini memberi Anda tempat yang konsisten untuk mencarinya. Ya, itu bisa mengganggu ketika ada makro yang sangat bersarang. Tetapi jika Anda membuat indentasi, pada akhirnya Anda akan mendapatkan kode yang tampak lebih aneh.

#if COND1
void foo() {
  #if COND2
  int i;
    #if COND3
  i = someFunction()
  cout << i << eol;
    #endif
  #endif
}
#endif
JaredPar
sumber
14
Alasan kode ini terlihat aneh adalah karena Anda telah membuat dua "aliran" lekukan. Saya akan membuat indentasi baris 4 satu level lagi, dan saya akan mengindentasi baris 6 & 7 dengan dua level lagi.
Kevin Laity
3
Setuju. Kadang-kadang saya bahkan memasang kawat gigi sehingga # jika terlihat seperti jika.
baash05
3
Aku berusaha sangat keras untuk mengatur kode saya sehingga memiliki tidak ada #ifdef garis di bagian mana saya memiliki kode aktual. Sebaliknya, jika saya membutuhkan hal-hal bersyarat, saya akan memasukkannya ke dalam fungsi yang difaktorkan atau memfaktorkan makro; jauh lebih jelas cara saya menemukan (yah, setidaknya bagi saya). Idealnya, semua bagian yang difaktorkan akan berada di file lain (header atau file sumber yang dikompilasi secara bersyarat; "kondisi" biasa adalah untuk platform apa kode dibuat).
Donal Fellows
2
Saya akan membuat indentasi baris 4 satu tingkat, dan baris 6 & 7 dua tingkat.
Rocketmagnet
3

Untuk contoh yang Anda berikan, mungkin tepat menggunakan lekukan untuk membuatnya lebih jelas, mengingat Anda memiliki struktur arahan bersarang yang kompleks.

Secara pribadi saya pikir itu berguna untuk menjaga mereka tidak menjorok sebagian besar waktu, karena arahan ini beroperasi secara terpisah dari sisa kode Anda. Direktif seperti #ifdef ditangani oleh pra-prosesor, sebelum kompilator pernah melihat kode Anda, jadi blok kode setelah perintah #ifdef bahkan tidak dapat dikompilasi .

Menjaga direktif secara visual terpisah dari kode Anda lebih penting ketika mereka diselingi dengan kode (daripada blok arahan khusus, seperti dalam contoh yang Anda berikan).

Daniel Fortunov
sumber
3
Dari sudut pandang IP, apa perbedaan antara sesuatu yang tidak dikompilasi dan sesuatu yang tidak tercapai karena jmp.
baash05
2

Saya sedang mengerjakan beberapa kode saat ini yang memiliki campuran mengerikan #defines, #ifdefs, #elses, #endifs, #etc. Semua ini sering dicampur dengan kode C normal. #Defines yang tidak membuat indentasi membuatnya sulit dibaca. Dan campuran kode indentasi dengan #defines non-indentasi adalah mimpi buruk.

Solusi umum adalah dengan mengomentari arahan, sehingga Anda dengan mudah mengetahui apa yang mereka maksud:

#ifdef FOO
/* a lot of code */
#endif /* FOO */

#ifndef FOO
/* a lot of code */
#endif /* not FOO */
Bastien Léonard
sumber
6
Saya telah melihat gaya itu, bos saya menggunakannya. Dan, seperti kode lainnya, itu hanya membuat berantakan. Bayangkan menghapus semua indentasi dari pernyataan if () normal Anda dan menggunakan komentar tersebut sebagai gantinya. Anda akan mengeluh bahwa Anda tidak dapat dengan mudah melihat apa yang mereka maksud.
Rocketmagnet
2

Di hampir semua kompiler C / CPP yang tersedia saat ini, hal itu tidak dibatasi. Terserah pengguna untuk memutuskan bagaimana Anda ingin menyelaraskan kode. Selamat membuat kode.

Hemanth
sumber
1
Jawaban yang layak. Bisakah Anda memperbaikinya dengan menambahkan beberapa referensi panduan gaya tertentu?
EtherDragon