Định nghĩa và hủy bỏ macro
#define PI 3.14 // Thay thế tại thời điểm biên dịch
#define T1 3+4 // Dễ gây nhầm lẫn
#define T2 (3+4) // Thêm dấu ngoặc để rõ nghĩa
float r = 1.0;
float area = PI * r * r;
int a = 2* T1; // Sau khi thay thế: int a = 2*3+4, không đúng ý
int a = 2* T2; // Sau khi thay thế: int a = 2*(3+4), đúng ý
#undef PI
float area = PI * r * r; // Lỗi: 'PI' chưa được khai báo
// Macro trong chuỗi sẽ không bị thay thế
printf("%s:%f\n", "PI", PI); // In ra PI: 3.14
// Tên macro phải là một định danh hợp lệ
#define 0x abcd // Lỗi: Không thể bắt đầu bằng số
// Các dấu ngoặc kép và đơn phải xuất hiện thành cặp
#define TEST11 "Z // Lỗi
#define TEST2 'Z // Lỗi
Macro có tham số
// Định nghĩa macro max và min với tham số #define MAX(a,b) (a>b ? a:b) #define MIN(a,b) (a<b ? a:b) // Sử dụng macro có tham số int sum = MAX(1,2) + MIN(1,2); // Sau khi thay thế: int sum = (1>2 ? 1:2) + (1<2 ? 1:2) // Số lượng tham số phải khớp với số lượng tham số đã định nghĩa MAX(1,2,3); // Báo lỗi #undef MAX // Hủy định nghĩa MAX MAX(1,2); // Lỗi: 'MAX' chưa được khai báo </pre>Định nghĩa macro nhiều dòng
// Định nghĩa macro hoán đổi giá trị trên nhiều dòng, sử dụng dấu gạch chéo ngược #define SWAP(a,b) do { \ int t = 0;\ t = a; \ a = b; \ b = t; \ } while(0)Những ký hiệu đặc biệt: #, ##, #@
#define CONCAT(a,b) a##b #define TO_CHAR(a) #@a #define TO_STRING(a) #a // a##b nối các tham số int n = CONCAT(123, 456); // Kết quả: n = 123456 char *str = CONCAT("abcd", "efg"); // Kết quả: str = "abcdefg" //@#a bao quanh tham số a bằng dấu nháy đơn, trả về một ký tự char ch1 = TO_CHAR(1); // Kết quả: ch = '1' char ch2 = TO_CHAR(123); // Lỗi: Dấu nháy đơn chỉ dùng cho một ký tự //#a bao quanh tham số a bằng dấu nháy kép, trả về một chuỗi char *str1 = TO_STRING(123); // str = "123"Một số macro thông dụng
Ngăn chặn việc bao gồm header file nhiều lần
#ifndef BODYDEF_H #define BODYDEF_H // Nội dung của header file #endifLấy giá trị byte hoặc word từ địa chỉ cụ thể
#include <stdio.h> // B đại diện cho byte #define MEM_B(x) ( *( (unsigned char *) (x) ) ) // W đại diện cho word, tương đương với int #define MEM_W(x) ( *( (int *) (x) ) ) int main() { int bTest = 0x123456; unsigned char m = MEM_B(&bTest); /*m=0x56*/ int n = MEM_W(&bTest); /*n=0x3456*/ return 0; }Lấy offset của một trường trong struct
#define OFFSET(type, field) ( (size_t) &((type *) 0)->field )Lấy kích thước của một trường trong struct
#define FIELD_SIZE(type, field) sizeof( ((type *) 0)->field )Lấy địa chỉ của biến (độ rộng word)
#define BYTE_PTR(var) ( (unsigned char *) (void *) &(var) ) #define WORD_PTR(var) ( (int *) (void *) &(var) )Chuyển đổi chữ cái thành chữ hoa
#define UPPERCASE(c) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )Kiểm tra xem ký tự có phải là số thập phân
#define IS_DECIMAL(c) ((c) >= '0' && (c) <= '9')Kiểm tra xem ký tự có phải là số thập lục phân
#define IS_HEX(c) ( ((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f') )Phương pháp ngăn chặn tràn số
#define INC_SAT(val) (val = ((val)+1 > (val)) ? (val)+1 : (val))Trả về số lượng phần tử trong mảng
#define ARRAY_SIZE(a) ( sizeof( (a) ) / sizeof( (a[0]) ) )Sử dụng macro để theo dõi và gỡ lỗi
Trong quá trình gỡ lỗi, chúng ta có thể đặt macro __DEBUG, hoặc sử dụng tùy chọn -D trong Makefile.
#define __DEBUGCách sử dụng:
#ifdef __DEBUG printf("%s", ...); #endifNgoài ra, chuẩn ANSI C có một số macro được định nghĩa sẵn, thường được sử dụng trong các câu lệnh printf, sprintf, v.v.:
__func__: Chèn tên hàm hiện tại vào mã nguồn;__LINE__: Chèn số dòng hiện tại vào mã nguồn;__FILE__: Chèn tên file hiện tại vào mã nguồn;__DATE__: Chèn ngày biên dịch vào mã nguồn;__TIME__: Chèn thời gian biên dịch vào mã nguồn;__STDC__: Được gán giá trị 1 nếu yêu cầu chương trình tuân thủ nghiêm ngặt chuẩn ANSI C;__cplusplus: Được định nghĩa khi viết chương trình C++.
Ví dụ sử dụng __cplusplus trong header file:
#ifndef _ZX_FUNC_H
#define _ZX_FUNC_H
#ifdef __cplusplus
extern "C" {
#endif
/* functions */
char *strdup (const char *s);
#ifdef __cplusplus
}
#endif
#endif
extern "C" cho phép mã C++ gọi hàm C, đảm bảo rằng hàm được biên dịch theo cách của C.