เหตุใด C ไลบรารีใช้แมโครและฟังก์ชันที่มีชื่อเดียวกัน


20

ฉันกำลังอ่าน 'ห้องสมุดมาตรฐาน C' โดย PJ Plauger ซึ่งน่าสนใจจริงๆ หนังสือเล่มนี้ไม่เพียง แต่อธิบายวิธีการใช้ห้องสมุด แต่ยังอธิบายถึงวิธีการนำไปใช้งาน

ฉันอ่านctype.hส่วนเสร็จแล้วและในส่วนหัวฟังก์ชั่นจะประกาศเป็นทั้งมาโครและฟังก์ชั่น ตัวอย่างเช่น

int isdigit(int);

แต่ยัง

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

ฉันไม่เข้าใจว่าทำไมใช้ทั้งคู่

นอกจากนี้ถ้าฉันพยายามสร้างctypeส่วนหัวที่กำหนดเองและการนำไปใช้ใหม่ฉันสามารถรวบรวมได้สำเร็จถ้าฉันลบแมโครออก (ใส่เครื่องหมายความคิดเห็นในการกำหนด)

แง่มุมนี้ไม่ได้อธิบายในหนังสือ ใครช่วยอธิบายหน่อยได้ไหม?


ไม่มีสิ่งใดในมาตรฐาน C ที่บังคับให้คอมไพเลอร์ใช้งานเป็นแมโคร มาโครน่าจะเป็นสิ่งตกค้างจากสมัยก่อนเมื่อ C ไม่มีอินไลน์ แม้ว่าคอมไพเลอร์สมาร์ทควรจะสามารถอินไลน์ฟังก์ชั่นนั้นถ้าจำเป็น แต่ไม่มีคำหลักแบบอินไลน์ที่ชัดเจน ดังนั้นมาโครที่มีฟังก์ชั่นเหมือนมีเพียงเพราะคอมไพเลอร์ถูกใช้งานโดยคนที่ไม่เก่งในการทำคอมไพเลอร์

คำตอบ:


23

แมโครมีประสิทธิภาพมากขึ้น (สมมุติ) เนื่องจากไม่เกี่ยวข้องกับการเรียกใช้ฟังก์ชัน สามารถปรับให้เหมาะสมได้ง่ายขึ้นเนื่องจากเกี่ยวข้องกับการค้นหาออฟเซ็ตของตัวชี้

การเรียกใช้ฟังก์ชั่นอนุญาตให้เชื่อมโยงกับไลบรารีเดียวกันแม้ว่าโปรแกรมนั้นจะถูกคอมไพล์โดยไม่มีนิยามแมโคร - ถ้ามันถูกคอมไพล์ด้วยส่วนหัวที่ต่างกันหรือเพียงแค่มีการประกาศอันธพาลภายในไฟล์ต้นฉบับ ตัวอย่างเช่นหากคุณมีคอมไพเลอร์ซึ่งมี ctype.h รุ่น "ปรับปรุง" ของใครบางคนที่ไม่มีมาโครฟังก์ชันจะยังคงมีอยู่เมื่อใช้งานจริง

ถ้าเราดูมาตรฐาน:

7.1.4 การใช้ฟังก์ชั่นห้องสมุด

ฟังก์ชั่นใด ๆ ที่ประกาศในส่วนหัวอาจถูกนำมาใช้เพิ่มเติมเป็นมาโครฟังก์ชั่นที่คล้ายกันในส่วนหัวดังนั้นหากฟังก์ชั่นห้องสมุดถูกประกาศอย่างชัดเจนเมื่อรวมส่วนหัวของมันไว้หนึ่งในเทคนิคที่แสดงด้านล่างนี้ รับผลกระทบจากแมโครดังกล่าว ฟังก์ชันแมโครใด ๆ สามารถยับยั้งภายในได้โดยใส่ชื่อของฟังก์ชันไว้ในวงเล็บเพราะชื่อนั้นจะไม่ตามด้วยวงเล็บซ้ายที่ระบุการขยายตัวของชื่อฟังก์ชันแมโคร ด้วยเหตุผลทางไวยากรณ์เดียวกันมันได้รับอนุญาตให้ใช้ที่อยู่ของฟังก์ชั่นห้องสมุดแม้ว่ามันจะถูกกำหนดเป็นแมโคร

นั่นหมายความว่าถ้าคุณเขียน:

int b = (isdigit)(c);

หรือ

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

จากนั้นคุณเรียกใช้ฟังก์ชันจริงไม่ใช่มาโคร คุณยังสามารถเขียนตามกฎหมาย:

#undef isdigit
int b = isdigit(c);

หรือ (ในไฟล์ต้นฉบับที่ไม่มี#include <ctype.h>โดยตรงหรือแบบต่อเนื่อง):

extern int isdigit(int);
int b = isdigit(c);

โปรแกรมสามารถคอมไพล์ได้อย่างไรโดยไม่มีข้อกำหนดของแมโคร?
user619818

extern int isdigit(int)ตัวอย่างเช่น@ user619818 ที่ใช้
ecatmur

ดังนั้นฉันชัดเจนคุณหมายถึงผู้ใช้ไม่มี # รวม <สิ่งใด> แต่เพิ่ม int isdigit (int) แทน ที่ด้านบนของไฟล์การใช้งาน ตกลงเพียงอ่านการตอบกลับของคุณอย่างถูกต้อง
user619818

การมีฟังก์ชั่น callable (เทียบกับรหัสมาโครแบบอินไลน์) ยังช่วยให้ภาษาอื่น ๆ เช่น python และ perl สามารถเชื่อมต่อกับฟังก์ชั่นเหล่านั้นได้
technosaurus
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.