Objective-C 매크로 정의 상세 설명

오픈 소스 프로젝트 의 소스 코드 를 즐겨 읽 는 사람 은 항상 발견 할 수 있 습 니 다.큰 신의 코드 에는 짧 고 효율 적 인 매크로 정의 가 있 습 니 다.클릭 하여 들 어가 보면 어렵 고 어렵 습 니 다.공 부 는 커 녕 이해 하 는 것 이 어렵 습 니 다.그러나 매크로 정의 자체 가 그렇게 어렵 지 않 지만 좋 은 매크로 를 쓰 는 데 풍부 한 경험 과 기술 이 필요 합 니 다.다음은 매크로 의 정 의 를 말 해 보 자.큰 신의 매크로 를 알 아 보 는 것 이 첫 걸음 이 고 가끔 쓰 는 것 도 엄 살 부 리 는 좋 은 방법 이다~
정의:
매크로 정 의 는 두 가지 로 나 뉜 다.하 나 는 대상 매크로(object-like macro)이 고 다른 하 나 는 함수 매크로(function-like macro)이다.
이름 에 따라 알 수 있 듯 이 대상 매크로 는 하나의 양 을 정의 하 는 데 사 용 됩 니 다.이 매크로 를 통 해 이 변 수 를 얻 을 수 있 습 니 다.예 를 들 어 우 리 는 pi 값 을 정의 합 니 다.\#define PI 3.1415926 여기 서 pi 값 을 사용 할 때 부동 소수점 을 하나 더 쓰 지 않 고 PI 로 이 상수 부동 소수점 을 기록 하 는 것 과 같 습 니 다.그 본질 적 인 의 미 는 코드 중의 PI 를 컴 파일 단계 에서 진정한 상수 로 바 꾸 는 것 이다.보통 자주 사용 하 는 상수,예 를 들 어 화면의 너비,시스템 버 전 번호 등 을 정의 하 는 데 사용 된다.그러나 주의해 야 할 것 은 표현 식 을 매크로 로 정의 할 때 매크로 의 표면 을 통 해 컴 파일 의 본질 을 봐 야 한 다 는 것 이다.예 를 들 어
#define MARGIN  10 + 20
그러나 그것 으로 폭 을 계산 할 때 MARGIN*2 를 사용 하면 결 과 는 원 하 는 것 이 아 닙 니 다.60 이 아 닌 50 을 얻 을 수 있 습 니 다.표현 식 을 펼 치면 볼 수 있 습 니 다.
MARGIN*2//전개 시 획득 가능
//  10 + 20 * 2  = 50
우 리 는 그것 의 연산 우선 순 위 를 고려 해 야 한다.해결 방식 은 매우 간단 하고,게다가 그것 의 바깥쪽 에 작은 괄호 를 더 해 야 한다.

#define MARGIN (10 + 20)
// MARGIN * 2
// (10 + 20) * 2 = 60
함수 매크로 의 역할 은 하나의 함수 와 같 습 니 다.매개 변 수 를 전달 할 수 있 고 매개 변 수 를 통 해 일련의 조작 을 할 수 있 습 니 다.예 를 들 어 우리 가 자주 사용 하 는 두 개의 수의 최대 치 를 계산 할 수 있 습 니 다.우 리 는 이렇게 정의 할 수 있 습 니 다.

#define MAX(A,B) A > B ? A : B
이렇게 쓰 는 것 은 문제 가 없 는 것 같 습 니 다.간단 한 비교 MAX(1,2)를 통 해 발견 하 는 것 도 문제 가 없 지만 누군가가 당신 의 매크로 를 사용 하여 더욱 복잡 한 계산 을 할 때 새로운 문제 가 발생 합 니 다.예 를 들 어 세 가지 수 치 를 계산 할 때 이렇게 쓸 수 있 습 니 다.

int a = 3;
int b = 2;
int c = 1;
MAX(a, b > c ? b : c) //
= 2
결 과 는 분명히 당신 이 원 하 는 것 이 아 닙 니 다.최대 치 는 분명히 3 입 니 다.그러나 계산 결 과 는 확실히 2 입 니 다.그 중에서 무슨 일이 발생 하여 계산 이 잘못 되 었 는 지 우 리 는 매크로 를 펼 쳐 서 결말 을 알 아 볼 수 있 습 니 다.다음은 매크로 의 전개 입 니 다.

MAX(a,b > c ? b : c);
//a > b > c ? b : c ? a : b > c ? b : c
//(a > (b > c ? b : c) ? a : b) > c ? b : c //         
//        
//( 3 > (2 > 1 ? 2 : 1 ) ? 3 : 2) > 1 ? 2 : 1
// (3 > 2 ? 3 : 2) > 1 ? 2 : 1
// 3 > 1 ? 2 : 1
문제 가 있 는 지,우선 순위 가 있 는 지 모두 가 알 아 보 았 을 것 입 니 다.그래서 여기 서 명심 하 세 요.어차피 괄호 두 개 를 더 써 도 피곤 하지 않 을 것 입 니 다.문제 가 발생 하 든 없 든 작은 괄호 를 쓰 는 것 은 결국 안전 합 니 다~
하지만 기발 한 글 씨 를 쓰 는 것 도 있 고,보기 만 해도 일리 가 있 는 것 같 아 요~

c = MAX(a++,b); // **           **
// c = a++ > b ? a++ : b
// c = 3++ > 2 ? 3++ : 2
// c = 4
// a = 5
이렇게 쓴 그 사람 이 얼마나 맞 았 든 지 간 에 아무런 문제 가 없 는 것 처럼 보이 기 때문에 우 리 는 이런 상황 을 처리 해 야 한다.그러나 우리 의 일반적인 작은 괄호 를 사용 하면 해결 할 수 없다.우 리 는 할당 확장({...})을 사용 해 야 한다.친구 가 이미 이런 용법 을 알 아 보 았 다 고 믿는다.우 리 는 이런 방법 으로 대상 을 계산 할 수 있다.변수 이름 을 낭비 하지 않 고 작은 범위 의 역할 영역 을 형성 하여 특수 한 값 을 계산 할 수 있다.

int a = ({
 int b = 10;
 int c = 20;
 b + c;
})
// a = 30;
int b; //     b c         
int c;
다시 지금 이 문제 로 돌아 가면 우 리 는 어떻게 이 매크로 를 바 꾸 어 이 구덩이 아버지의 서법 에 적응 시 켜 야 합 니까?
#define MAX(A,B) ({__typeof(A) __a = (A);__typeof(B) __b = (B); __a > __b ? __a : __b; })
__type:of()는 같은 유형의 변수 값 으로 전환 하면 이 문 제 를 완벽 하 게 해결 할 수 있 습 니 다.하지만 잘 발생 하지 않 는 의외 의 사고 가 있 습 니 다.위 를 통 해 알 수 있 듯 이 우 리 는 새로운 변 수 를 생 성 했 습 니 다a, __b.어떻게 누군가가 사용 하 는 지a,__b.변수 이름 을 반복 해서 잘못 컴 파일 해 야 합 니 다.만약 누군가가 이렇게 사용한다 면 키 보드 를 들 고 그의 얼굴 을 때 릴 수 있 습 니 다.그 이 유 는 당연히 가 아 닙 니 다.a.당신 의 매크로 를 잘못 만 들 었 습 니 다.대신a.도대체 무슨 뜻 인지 변수 이름 의 중요성 은 말 하지 않 아 도 알 수 있 습 니 다.코드 를 보 는 사람과 원한 이 있 지 않 으 면 의미 있 는 변수 이름 을 사용 하 십시오.다음은 공식 적 인 MAX 가 어떻게 실현 되 는 지 살 펴 보 겠 습 니 다.

#define __NSX_PASTE__(A,B) A##B

#if !defined(MAX)
  #define __NSMAX_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__b,L) : __NSX_PASTE__(__a,L); })
  #define MAX(A,B) __NSMAX_IMPL__(A,B,__COUNTER__)
#endif

이것 은 Function 프레임 워 크 의 MAX 정의 입 니 다.저희 가 한 걸음 한 걸음 해석 해 보 겠 습 니 다.먼저 보 이 는 것 은?
#define __NSX_PASTE__(A,B) A##B
//A 와 B 를 연결 합 니 다.
A 와 B 를 연결 하여 하나의 문자열 을 만 드 는 역할 을 합 니 다.예 를 들 어 A\#\#12 는 A12 가 됩 니 다.
이어서 우 리 는 세 개의 매개 변수 가 있 는 매크로 정 의 를 보 았 다.NSMAX_IMPL__(A,B,__COUNTER__)

#if !defined(MAX)
  #define __NSMAX_IMPL__(A,B,L) ({ __typeof__(A) __NSX_PASTE__(__a,L) = (A); __typeof__(B) __NSX_PASTE__(__b,L) = (B); (__NSX_PASTE__(__a,L) < __NSX_PASTE__(__b,L)) ? __NSX_PASTE__(__b,L) : __NSX_PASTE__(__a,L); })
  #define MAX(A,B) __NSMAX_IMPL__(A,B,__COUNTER__)
#endif
우리 먼저 설명 하 자COUNTER__무엇 입 니까?COUNTER__사전 컴 파일 매크로 입 니 다.컴 파일 할 때마다 1 을 추가 합 니 다.그러면NSX_PASTE__(__b,__CONNTER__)생 성 된 변수 이름 은 중복 되 기 쉽 지 않 지만,그래도 좀 위험 합 니 다.바로 당신 이 변수 이름 을 지 으 면a20,그럼 정말 어 쩔 수 없어~
가 변 매개 변수 매크로
가 변 매개 변 수 를 말하자면 우리 가 가장 많이 사용 하 는 방법 은 NSLog(...)는 가 변 매개 변수 입 니 다.가 변 매개 변 수 는 매개 변수의 개수 가 정 해 지지 않 았 다 는 것 을 의미 합 니 다.NSLog 는 우리 가 디 버 깅 할 때 중요 한 도구 로 서 너무 쓸모없는 것 입 니 다.해당 하 는 시간 과 매개 변수 정 보 를 인쇄 할 수 밖 에 없습니다.파일 이름,줄 수,방법 명 등 중요 한 정 보 는 제공 되 지 않 았 습 니 다.오늘 우 리 는 이것으로 슈퍼 판 NSLog 宏 을 실현 합 니 다~~

#define NSLog(format, ...) do { fprintf(stderr, "<%s : %d> %s
", \ [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__); \ (NSLog)((format), ##__VA_ARGS__); \ fprintf(stderr, "-------
"); \ } while (0)
우선 이 매크로 의 정 의 를 보면 NSLog(format,...)에 있 는...이것 이 바로 가 변 매개 변수 이 고VA__ARGS__format 을 제외 하고 남 은 모든 매개 변 수 를 발견 한 다음 에 우 리 는 do{}while(0)순환 을 사용 한 것 을 발견 했다.이 순환 은 한 번 만 실행 하면 멈 추 는 것 을 의미한다.쓸데없는 소리 가 난다.우리 의 목적 은 한 번 만 실행 하 는 것 이다.그러나 이렇게 쓰 는 것 은 방어 식 프로 그래 밍 을 하기 위해 서 이다.만약 에 누군가가 이렇게 쓰 면
if (100 > 99)
  NSLog(@"%@",@"Fuck");
어떻게 든 실 행 된 후 두 개의 인쇄 가 발생 할 것 입 니 다.문제 가 발생 한 것 은 모두 가 알 고 있 을 것 입 니 다.그러면 우 리 는{}을 직접 사용 하여 확대 하면 되 지 않 습 니까?실제 작업 을 한 후에 이 문 제 를 해결 한 것 은 사실 입 니 다.그러나 다시 한 번 확장 하면 우리 가 if{}else if{}을 사 용 했 을 때 또 새로운 문제 가 발생 할 것 입 니 다.

if (100 > 99)
 NSLog(@"%@",@"Fuck");
else {
}
//      
if (100 > 99)
{ fprintf(stderr, "<%s : %d> %s
", [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__); (NSLog)((format), ##__VA_ARGS__); fprintf(stderr, "-------
");}; else { }
컴 파일 오류 가 발생 했 습 니 다.NSLog 가 뒤 따 를 것 입 니 다.우리 가{}을 직접 사용 하면 컴 파일 할 때 외부 에 추가 합 니 다.컴 파일 오류 가 발생 했 습 니 다.do{}while(0)순환 을 사용 하면 이 문제 가 발생 하지 않 습 니 다.

if (100 > 99)
 do { fprintf(stderr, "<%s : %d> %s
", [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __func__); (NSLog)((format), ##__VA_ARGS__); fprintf(stderr, "-------
");} while(0); else { }
이 자리 에서 문 제 를 해결 하 는 데 차이 가 많 지 않 습 니 다.내부 구 조 를 보 세 요.FILE__컴 파일 된 파일 경로 입 니 다.LINE__줄 수 입 니 다.func__컴 파일 하 는 방법 명 입 니 다.아래 에서 우 리 는 또 보 았 습 니 다.
(NSLog)((format), ##__VA_ARGS__);
\##위 에서 이미 보 았 습 니 다.여기 서 의 역할 차이 가 많 지 않 습 니 다.연결 의 뜻 이기 도 합 니 다.VA_ARGS__남 은 모든 인자 입 니 다.\#연결 하면 NSLog(format,VA_ARGS__)자,이것 이 NSLog 의 방법 입 니 다.하지만 세부 사항 을 발견 한 사람 이 있 는 지 모 르 겠 습 니 다.만약VA_ARGS__비어 있 으 면 NSLog(format,)가 되 는 것 이 아니 겠 습 니까?분명 컴 파일 이 틀 릴 것 입 니 다.하지만 애플 의 신 들 은 해결 방법 을 생각 하고 있 었 습 니 다.만약VA_ARGS__비어 있 으 면 여기 서\##앞 에 있 는 것 을 삼 켜 버 리 고 문제 가 되 지 않 습 니 다.그리고 우 리 는 이 강력 한 NSLog()를 사용 할 수 있 습 니 다.
이어서 다 중 매개 변수 함수 사용 에 대해 말씀 드 리 겠 습 니 다.

- (void)say:(NSString *)code,... {  
  va_list args;
  va_start(args, code);
  NSLog(@"%@",code);
  while (YES) {
    NSString *string = va_arg(args, NSString *);
    if (!string) {
      break;
    }
    NSLog(@"%@",string);
  }
  va_end(args);
}
우 리 는 먼저 바 를 정의 할 수 있다.list args 를 통 해 다 중 매개 변수 args 를 정의 하고 vastart(args,code)에서 값 을 추출 합 니 다.code 는 첫 번 째 값 입 니 다.vaarg(args,NSString*)에서 추출 한 값 형식 을 정의 합 니 다.추출 방식 은 생 성기 와 같 습 니 다.추출 한 후에 va 를 호출 합 니 다.end(args)를 닫 습 니 다.이것 이 바로 전체 과정 입 니 다.평소에 이런 방법 을 거의 사용 하지 않 습 니 다.좋 은 실 용적 인 방법 이 있 으 면 댓 글 을 달 아 주세요~~
읽 어 주 셔 서 감사합니다. 여러분 에 게 도움 이 되 기 를 바 랍 니 다.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기