Objective-C ตัวประมวลผลล่วงหน้า
Objective-C Preprocessorไม่ได้เป็นส่วนหนึ่งของคอมไพเลอร์ แต่เป็นขั้นตอนแยกต่างหากในกระบวนการคอมไพล์ ในแง่ที่เข้าใจง่าย Objective-C Preprocessor เป็นเพียงเครื่องมือทดแทนข้อความและสั่งให้คอมไพเลอร์ทำการประมวลผลล่วงหน้าที่จำเป็นก่อนการคอมไพล์จริง เราจะอ้างถึง Objective-C Preprocessor ว่า OCPP
คำสั่งพรีโปรเซสเซอร์ทั้งหมดเริ่มต้นด้วยสัญลักษณ์ปอนด์ (#) ต้องเป็นอักขระ nonblank ตัวแรกและเพื่อความสามารถในการอ่านคำสั่งพรีโปรเซสเซอร์ควรเริ่มต้นในคอลัมน์แรก ส่วนต่อไปนี้แสดงรายการคำสั่งก่อนตัวประมวลผลที่สำคัญทั้งหมด -
ซีเนียร์ | คำสั่งและคำอธิบาย |
---|---|
1 | #define แทนที่มาโครตัวประมวลผลล่วงหน้า |
2 | #include แทรกส่วนหัวเฉพาะจากไฟล์อื่น |
3 | #undef ไม่ได้กำหนดมาโครตัวประมวลผลล่วงหน้า |
4 | #ifdef ส่งคืนค่าจริงหากกำหนดมาโครนี้ |
5 | #ifndef ส่งคืนค่าจริงหากไม่ได้กำหนดมาโครนี้ |
6 | #if ทดสอบว่าเงื่อนไขเวลาคอมไพล์เป็นจริงหรือไม่ |
7 | #else ทางเลือกสำหรับ #if |
8 | #elif #else an #if ในหนึ่งคำสั่ง |
9 | #endif สิ้นสุดเงื่อนไขก่อนตัวประมวลผล |
10 | #error พิมพ์ข้อความแสดงข้อผิดพลาดบน stderr |
11 | #pragma ออกคำสั่งพิเศษไปยังคอมไพลเลอร์โดยใช้วิธีการมาตรฐาน |
ตัวอย่างตัวประมวลผลล่วงหน้า
วิเคราะห์ตัวอย่างต่อไปนี้เพื่อทำความเข้าใจคำสั่งต่างๆ
#define MAX_ARRAY_LENGTH 20
คำสั่งนี้บอกให้ OCPP แทนที่อินสแตนซ์ของ MAX_ARRAY_LENGTH ด้วย 20 ใช้#defineสำหรับค่าคงที่เพื่อเพิ่มความสามารถในการอ่าน
#import <Foundation/Foundation.h>
#include "myheader.h"
คำสั่งเหล่านี้บอกให้ OCPP ได้รับรากฐาน h จาก Foundation Frameworkและเพิ่มข้อความลงในไฟล์ต้นฉบับปัจจุบัน บรรทัดถัดไปบอกให้รับ OCPPmyheader.h จากโลคัลไดเร็กทอรีและเพิ่มเนื้อหาลงในซอร์สไฟล์ปัจจุบัน
#undef FILE_SIZE
#define FILE_SIZE 42
สิ่งนี้บอกให้ OCPP ยกเลิกการกำหนด FILE_SIZE ที่มีอยู่และกำหนดเป็น 42
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
สิ่งนี้จะบอกให้ OCPP กำหนด MESSAGE ก็ต่อเมื่อยังไม่ได้กำหนด MESSAGE ไว้
#ifdef DEBUG
/* Your debugging statements here */
#endif
สิ่งนี้บอกให้ OCPP ดำเนินการตามคำสั่งที่แนบมาหากมีการกำหนด DEBUG สิ่งนี้มีประโยชน์หากคุณส่งแฟล็ก -DDEBUGไปยังคอมไพเลอร์ gcc ในขณะคอมไพล์ สิ่งนี้จะกำหนด DEBUG เพื่อให้คุณสามารถเปิดและปิดการดีบักได้ทันทีในระหว่างการคอมไพล์
มาโครที่กำหนดไว้ล่วงหน้า
ANSI C กำหนดมาโครจำนวนหนึ่ง แม้ว่าแต่ละมาโครจะพร้อมใช้งานสำหรับการเขียนโปรแกรมของคุณ แต่ก็ไม่ควรแก้ไขมาโครที่กำหนดไว้ล่วงหน้าโดยตรง
ซีเนียร์ | มาโครและคำอธิบาย |
---|---|
1 | __DATE__ วันที่ปัจจุบันเป็นอักขระลิเทอรัลในรูปแบบ "MMM DD YYYY" |
2 | __TIME__ เวลาปัจจุบันเป็นอักขระลิเทอรัลในรูปแบบ "HH: MM: SS" |
3 | __FILE__ ซึ่งมีชื่อไฟล์ปัจจุบันเป็นสตริงลิเทอรัล |
4 | __LINE__ ซึ่งประกอบด้วยหมายเลขบรรทัดปัจจุบันเป็นค่าคงที่ทศนิยม |
5 | __STDC__ กำหนดเป็น 1 เมื่อคอมไพเลอร์เป็นไปตามมาตรฐาน ANSI |
ลองดูตัวอย่างต่อไปนี้ -
#import <Foundation/Foundation.h>
int main() {
NSLog(@"File :%s\n", __FILE__ );
NSLog(@"Date :%s\n", __DATE__ );
NSLog(@"Time :%s\n", __TIME__ );
NSLog(@"Line :%d\n", __LINE__ );
NSLog(@"ANSI :%d\n", __STDC__ );
return 0;
}
เมื่อรหัสดังกล่าวอยู่ในไฟล์ main.m ถูกรวบรวมและดำเนินการจะให้ผลลัพธ์ดังต่อไปนี้ -
2013-09-14 04:46:14.859 demo[20683] File :main.m
2013-09-14 04:46:14.859 demo[20683] Date :Sep 14 2013
2013-09-14 04:46:14.859 demo[20683] Time :04:46:14
2013-09-14 04:46:14.859 demo[20683] Line :8
2013-09-14 04:46:14.859 demo[20683] ANSI :1
ตัวดำเนินการก่อนโปรเซสเซอร์
ตัวประมวลผลล่วงหน้า Objective-C มีตัวดำเนินการต่อไปนี้เพื่อช่วยคุณในการสร้างมาโคร -
ความต่อเนื่องของมาโคร (\)
โดยปกติมาโครจะต้องอยู่ในบรรทัดเดียว ตัวดำเนินการต่อเนื่องแมโครใช้เพื่อดำเนินการต่อมาโครที่ยาวเกินไปสำหรับบรรทัดเดียว ตัวอย่างเช่น -
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
สตริง (#)
ตัวดำเนินการ stringize หรือ number-sign ('#') เมื่อใช้ภายในนิยามมาโครจะแปลงพารามิเตอร์มาโครเป็นค่าคงที่ของสตริง ตัวดำเนินการนี้สามารถใช้ได้เฉพาะในมาโครที่มีอาร์กิวเมนต์หรือรายการพารามิเตอร์ที่ระบุ ตัวอย่างเช่น -
#import <Foundation/Foundation.h>
#define message_for(a, b) \
NSLog(@#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะให้ผลลัพธ์ดังนี้ -
2013-09-14 05:46:14.859 demo[20683] Carole and Debra: We love you!
การวางโทเค็น (##)
ตัวดำเนินการวางโทเค็น (##) ภายในนิยามมาโครรวมสองอาร์กิวเมนต์ อนุญาตให้โทเค็นสองโทเค็นที่แยกจากกันในนิยามมาโครรวมเป็นโทเค็นเดียว ตัวอย่างเช่น -
#import <Foundation/Foundation.h>
#define tokenpaster(n) NSLog (@"token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะให้ผลลัพธ์ดังนี้ -
2013-09-14 05:48:14.859 demo[20683] token34 = 40
มันเกิดขึ้นได้อย่างไรเนื่องจากตัวอย่างนี้ส่งผลให้เกิดผลลัพธ์จริงต่อไปนี้จากตัวประมวลผลล่วงหน้า -
NSLog (@"token34 = %d", token34);
ตัวอย่างนี้แสดงการต่อโทเค็น ## n เข้ากับโทเค็น 34 และที่นี่เราได้ใช้ทั้งสองอย่าง stringize และ token-pasting.
ตัวดำเนินการที่กำหนด ()
ตัวประมวลผลล่วงหน้า definedตัวดำเนินการถูกใช้ในนิพจน์ค่าคงที่เพื่อพิจารณาว่าตัวระบุถูกกำหนดโดยใช้ #define หรือไม่ หากมีการกำหนดตัวระบุที่ระบุไว้ค่าจะเป็นจริง (ไม่ใช่ศูนย์) หากไม่ได้กำหนดสัญลักษณ์ไว้ค่าจะเป็นเท็จ (ศูนย์) ระบุตัวดำเนินการดังต่อไปนี้ -
#import <Foundation/Foundation.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
NSLog(@"Here is the message: %s\n", MESSAGE);
return 0;
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะให้ผลลัพธ์ดังนี้ -
2013-09-14 05:48:19.859 demo[20683] Here is the message: You wish!
มาโครที่กำหนดพารามิเตอร์
หนึ่งในฟังก์ชันที่มีประสิทธิภาพของ OCPP คือความสามารถในการจำลองฟังก์ชันโดยใช้มาโครที่กำหนดพารามิเตอร์ ตัวอย่างเช่นเราอาจมีรหัสเพื่อยกกำลังสองจำนวนดังนี้ -
int square(int x) {
return x * x;
}
เราสามารถเขียนโค้ดด้านบนโดยใช้มาโครได้ดังนี้ -
#define square(x) ((x) * (x))
ต้องกำหนดมาโครที่มีอาร์กิวเมนต์โดยใช้ #defineคำสั่งก่อนที่จะใช้งานได้ รายการอาร์กิวเมนต์อยู่ในวงเล็บและต้องตามด้วยชื่อแมโครทันที ไม่อนุญาตให้ใช้ช่องว่างระหว่างชื่อมาโครและวงเล็บเปิด ตัวอย่างเช่น -
#import <Foundation/Foundation.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
NSLog(@"Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
เมื่อโค้ดด้านบนถูกคอมไพล์และเรียกใช้งานจะให้ผลลัพธ์ดังนี้ -
2013-09-14 05:52:15.859 demo[20683] Max between 20 and 10 is 20