Mengapa perpustakaan C menggunakan makro dan fungsi dengan nama yang sama?

20

Saya membaca 'The Standard C Library' oleh PJ Plauger yang sangat menarik. Buku ini menjelaskan tidak hanya bagaimana MENGGUNAKAN perpustakaan tetapi juga bagaimana itu diterapkan.

Saya telah selesai membaca ctype.hbagian dan di header fungsi dinyatakan sebagai fungsi makro DAN. Sebagai contoh

int isdigit(int);

tetapi juga

#define isdigit(c) (_Ctype[(int)(c)] & _DI)

Saya tidak mengerti mengapa KEDUA digunakan?

Juga, jika saya mencoba membuat ulang ctypetajuk dan implementasi kustom saya sendiri , saya hanya dapat mengkompilasi dengan sukses jika saya menghapus makro (komentar di luar define).

Aspek ini tidak benar-benar dijelaskan dalam buku ini. Bisakah seseorang tolong jelaskan?

pengguna619818
sumber
Tidak ada dalam standar C yang memaksa kompiler untuk mengimplementasikannya sebagai makro. Makro kemungkinan besar merupakan residu dari masa lalu ketika C tidak memiliki inlining. Padahal kompiler pintar harus bisa inline fungsi itu jika diperlukan, tanpa kata kunci inline eksplisit. Jadi makro seperti fungsi hanya ada karena kompiler diimplementasikan oleh seseorang yang tidak brilian dalam membuat kompiler.

Jawaban:

23

Makro (lebih tepatnya) lebih efisien, karena tidak melibatkan pemanggilan fungsi. Ini dapat dioptimalkan dengan lebih mudah, karena hanya melibatkan lookup offset offset.

Panggilan fungsi memungkinkan menghubungkan ke perpustakaan yang sama bahkan jika program dikompilasi tanpa definisi makro - jika dikompilasi dengan header yang berbeda, atau hanya dengan deklarasi nakal di dalam file sumber. Jika, misalnya, Anda memiliki kompiler yang memiliki versi "perbaikan" seseorang dari ctype.h yang tidak memiliki makro, fungsi tersebut akan tetap ada saat runtime untuk digunakan.

Jika kita melihat standarnya:

7.1.4 Penggunaan fungsi perpustakaan

Setiap fungsi yang dideklarasikan dalam header dapat diimplementasikan sebagai makro mirip fungsi yang didefinisikan dalam header, jadi jika fungsi perpustakaan dideklarasikan secara eksplisit ketika headernya dimasukkan, salah satu teknik yang ditunjukkan di bawah ini dapat digunakan untuk memastikan deklarasi tidak dipengaruhi oleh makro seperti itu. Setiap definisi makro dari suatu fungsi dapat ditekan secara lokal dengan melampirkan nama fungsi dalam tanda kurung, karena nama tersebut kemudian tidak diikuti oleh tanda kurung kiri yang menunjukkan perluasan nama fungsi makro. Untuk alasan sintaksis yang sama, diizinkan untuk mengambil alamat fungsi pustaka bahkan jika itu juga didefinisikan sebagai makro.

Itu artinya jika Anda menulis:

int b = (isdigit)(c);

atau

int (*f)(int) = &isdigit;
int b = f(c);

maka Anda menjalankan fungsi yang sebenarnya, bukan makro. Anda juga dapat secara legal menulis:

#undef isdigit
int b = isdigit(c);

atau (dalam file sumber tidak memiliki #include <ctype.h>secara langsung atau transitif):

extern int isdigit(int);
int b = isdigit(c);
ecatmur
sumber
Bagaimana program dikompilasi TANPA definisi makro?
user619818
@ user619818 menggunakan extern int isdigit(int), misalnya.
ecatmur
Supaya saya jelas, maksud Anda pengguna tidak memiliki #include <wh whatever> tetapi malah menambahkan int isdigit (int); di atas file implementasi. OK, baca saja respons Anda dengan benar.
user619818
Memiliki fungsi yang dapat dipanggil (vs. kode makro inline) juga memungkinkan bahasa lain seperti python dan perl untuk berinteraksi dengan fungsi-fungsi tersebut
technosaurus