당신이 경험 한 최악의 실제 매크로 / 전 처리기 남용은 무엇입니까?


176

무엇이입니다 최악의 실제 매크로 / 사전 - 프로세서는 (IOCCC 답변 * 하하 *을 고안없는하시기 바랍니다)를 건너 어느 한 학대?

재미있는 내용이라면 짧은 스 니펫이나 스토리를 추가하십시오. 사람들에게 항상 "매크로를 사용하지 마십시오"라고 말하는 대신 무언가를 가르치는 것이 목표입니다.


추신 : 나는 전에 매크로를 사용했지만 ... 실제로 솔루션이있을 때 (실제 솔루션이 인라인 되었더라도 매크로와 유사하게 됨) 결국 매크로를 제거합니다.


보너스 : 매크로가 매크로가 아닌 솔루션보다 실제로 더 나은 예를 들어보십시오.

관련 질문 : C ++ 매크로는 언제 유익합니까?


내가 매크로의 손에 겪었던 만연한 학대에 주목 한 +1.
i_am_jorf

37
#define true false // 행복한 디버깅 :)
n0rd

커뮤니티 위키는 아무도이 질문 또는 그 답변에 대한 상 / 하 투표로 명성을 얻거나 잃지 않을 것임을 의미합니다. 많은 사람들이 이와 같은 질문을 저렴하고 쉽게 평판을 얻는 방법으로보고 있으므로 커뮤니티 위키로 표시하면 사람들이 모든 형태를 구부리고 닫을 가능성이 줄어 듭니다.
Graeme Perrow 13:19에

2
"사람들은 모양이 모두 구부러져 닫힙니다": 스택 오버플로에서 유머러스하고 재미있는 콘텐츠를 원하지 않는다는 것을 의미합니까?
Trevor Boyd Smith

2
간단히 말해, 전처리 기는 언어의 일부이므로 다른 것과 마찬가지로 사용하기에 악의적이지 않습니다.
Mr. Boy

답변:


410

메모리에서 다음과 같이 보였습니다.

#define RETURN(result) return (result);}

int myfunction1(args) {
    int x = 0;
    // do something
    RETURN(x)

int myfunction2(args) {
    int y = 0;
    // do something
    RETURN(y)

int myfunction3(args) {
    int z = 0;
    // do something
    RETURN(z)

예, 맞습니다. 어떤 기능에도 닫는 괄호가 없습니다. 구문 강조는 혼란 스러웠으므로 vi를 사용하여 편집했습니다 (vim이 아니라 구문 색상이 있습니다).

그는 주로 어셈블리 언어로 일한 러시아 프로그래머였습니다. 그는 이전에 메모리가 매우 제한된 시스템에서 작업했기 때문에 가능한 한 많은 바이트를 절약하는 것에 열광적이었습니다. "위성에 대한 것이 었습니다. 바이트 수가 매우 적기 때문에 각 바이트를 여러 가지 용도로 사용합니다." (비트 피들 링, 숫자 값으로 기계 명령 바이트 재사용) 어떤 종류의 위성을 찾으려고했을 때, "궤도 위성을 만들었습니다. 궤도를 만들기 위해"

그는 또 다른 두 가지 단점이 있었다. "누가보고 있는지 알기 위해"모니터 위에 볼록한 거울이 있었고, 가끔 의자에서 갑자기 10 번 팔 굽혀 펴기를하기 위해 갑자기 빠져 나갔다. 그는이 마지막 내용을 "컴파일러가 코드에서 오류를 발견했습니다. 이것은 처벌입니다"라고 설명했습니다.


87
"컴파일러가 코드에서 오류를 발견했습니다. 이것은 처벌입니다." !! 회사는 당신을 발견했습니다 ... 동료 직원들에 대한 처벌!
학습

227
소비에트 러시아에서 프로그램은 당신을 컴파일합니다!
Crashworks

53
컴파일러 오류 "처벌"에 대해 읽었을 때 가장 먼저 생각한 것은 "Dobby는 손을 다림질해야했습니다"였습니다.
Graeme Perrow

124
컴파일러가 코드에서 오류를 발견 할 때마다 10 명의 푸시 업을 수행하면 프로그래머 (자체 포함)가 훨씬 적합하다고 생각합니다. 또한 컴파일에 의한 테스트 발생을 줄일 수 있습니다.
MikeyB 2016 년

5
그 사람은 굉장한 소리. 그러나 그렇습니다. 코드 크기를 어떻게 개선해야하는지 모르겠습니다.
jalf

274

내 최악 :

#define InterlockedIncrement(x) (x)++
#define InterlockedDecrement(x) (x)--

일부 바보는 이것을 헤더 파일에 넣었 기 때문에 이틀 동안 평생 멀티 스레드 COM 참조 계산 문제를 추적했습니다. 당시 내가 일했던 회사는 언급하지 않겠습니다.

이 이야기의 도덕? 무언가를 이해하지 못하면 문서를 읽고 그것에 대해 배우십시오. 그냥 버리지 마십시오.


146
@Joshua : 멀티 스레드 환경에서이 코드를 실행하면 실수로 그렇게 할 수 있습니다.
1800 INFORMATION

11
"무엇을 이해하지 못하면 문서를 읽고 그것에 대해 배우십시오. 그냥 옮기지 마십시오." -AMEN!
Paul Alexander

2
1800 정보 @ : 내가 당신에게 한 줄 수없는 이유입니다, 당신은 단지 잃게 투표 거라고 생각; P
WKF

5
비 C ++ 프로그래머로 나를 용서하십시오 : 여기서 스레드 안전 함수가 스레드 안전 기능이 아닌 함수로 변환되는 주요 문제입니까? 또는 InterlockedIncrement가 포인터를 기대하므로 이제 가리키는 포인터 대신 포인터를 늘릴 것입니까? 아니면 둘다?
Tim Pietzcker

38
문제는 InterlockedIncrement가 일반적으로 Windows API에 정의 된 원자 함수라는 것입니다. 따라서 사람들이 InterlockedIncrement를 호출하면 원자 적으로 실행될 수있는 함수를 호출해야합니다. 대신, 누군가가 같은 이름을 가진 매크로를 정의 일반, 비 원자 증가에 어떤 평가됩니다
jalf

166
#define ever (;;)
for ever { 
   ...
}

52
<#define forever for (;;)>를 선호하므로 <forever {...}>을 (를) 작성할 수 있습니다.
paxdiablo

누군가 내가 영원히 잃어버린 표식으로 학교에 갔다 ... 그는 교과서에서와 같이 질식 당했다 :-)
TofuBeer

6
Pax의 제안은 K & R과 직접적이지 않습니까? 그래도 노력할 가치가 없다고 말하고 싶습니다.
Jon Ericson

실제로 전혀 나쁘지 않습니다. 나는 for (;;)관용구를 사용하지 않고 , 그렇지 않으면 즉시이 매크로를 코드에 추가합니다.
AnT

1
@hayalci : emacs lisp (그리고 몇몇 일반적인 lisp 구현)에서 가능 (defmacro ever ())하다면(require 'cl (ever))
Joe D

145
#include <iostream>
#define System S s;s
#define public
#define static
#define void int
#define main(x) main()
struct F{void println(char* s){std::cout << s << std::endl;}};
struct S{F out;};

public static void main(String[] args) {
  System.out.println("Hello World!");
}

도전 과제 : 더 적은 수의 정의와 구조체로 누구나 할 수 있습니까? ;-)


19
방금 java-c 변환기를 작성했습니다! 호 레이!
Andreas Petersson

25
"공세"로보고되었습니다. (I kid!)
Annika Backstrom 2016 년

40
그것은 엄청나게 아름답거나 아름답습니다.
Chris Lutz가

38
@ 마크 - 그것은 선언 publicstatic as nothing, 같은 void` intmain(x)같은 main(), 그래서 public static void main(String[] args)으로 회전은 int main(). 그 다음 System으로 변하기 S s;s때문에 System.out.println("Hello World!");회전에 S s; s.out.println("Hello World!");이는 호출 println의 기능 F에서 구조체 S구조체.
Chris Lutz

2
: 이것 좀 봐 mailcom.com/ioccc/chia/chia.c (다운로드하고 컴파일)
로베르토 Bonvallet

130
#define private public

전에 해봤어요 때로는 변경 할 수없는 일부 타사 코드에서 멤버 변수를 수정하거나 함수를 재정의해야하기 때문에 접근자를 제공하지 않았습니다.
Michael Kristofik 2016 년

30
개체 테스트의 유령은 밤에 객체 디자인의 유령이 당신을 괴롭힐지라도 유용 할 수 있습니다.
Epaga

12
흠, 정의되지 않은 동작, 1- 정의 규칙 위반, 잠재적 인 레이아웃 차이. 응,이기는 사람이야
David Thornley

10
따라서 개인 및 공개 자료에는 액세스 할 수 있지만 보호 된 자료에는 액세스 할 수 없으며 class키워드와 첫 번째 액세스 수정 자 사이에있는 자료에는 액세스 할 수 없습니다 .
Ken Bloom

3
@Ken :#define class struct #define protected public
Yakov Galka

107
#define if while

누군가에게 농담을했고, 영향을받은 사람들에 의해 재미있는 것이 발견되지 않았습니다.


22
더 정직한 경우 #define.
starblue

7
우리는 당신의 진술을 명확히해야합니다. 영향을받은 사람들에 의해 재미있는 것이 발견되지 않았습니다 . :-)
Andrew Shepherd

6
숙제를 할 때 종종 선생님들을 귀찮게하기 위해 이런 종류의 일을 의도적으로했습니다.
pyon

15
이것은 좋은 장난이지만 "else"문이 있으면 컴파일되지 않습니다. #define if (x) if (true)가 가장 효과적이라는 것을 알았습니다.
Graphics Noob

32
나는 항상 #define sizeof (x) rand ()를 선호했습니다
Jon

106

끔찍한 :

#define begin {
#define end }
/* and so on */

진심으로, 파스칼로 코딩하려면 파스칼 컴파일러를 구입하고 아름다운 C 언어를 파괴하지 마십시오.


45
이제 당신은 영리하고 충분한 헤더 파일로 어떤 언어를 시뮬레이션 할 수 있는지 궁금합니다.
Bill the Lizard

47
C는 아름답 지 않다. 오히려 추악합니다.
rlbond

27
그 아름다움은 단순함에 있습니다. 그것은 어셈블리 언어의 가독성과 결합 된 어셈블리 언어의 모든 속도를 가지고 있다고합니다 ...- :) 팽창 된 C ++보다 선호합니다 (거대한 라이브러리로 인해 하루 종일 Java를 선호하지만).
paxdiablo

9
아니야 Bourne 쉘에 대한 Bourne의 원래 소스를 찾으십시오. 그는 정확하게 이런 종류의 나쁜 놈 ALGOL과 같은 혼란을 얻었습니다.
RBerteig

3
#에 대한 DO 정의 (int _i = 0; _i <= 1; ++ _ i) {if (_i == 1) //// LINE BREAK //// #define IF (cond); if (! (cond)) break; } //// LINE BREAK //// DO printf ( "a") IF (1 == 2);
Adrian Panasiuk

93

'건축가', 매우 겸손한 사람, 당신은 유형을 알고 있습니다.

#define retrun return

그는 빠른 타이핑을 좋아했기 때문에 뇌 외과 의사는 그보다 똑똑한 사람들 (거의 모든 사람)에게 소리를 지르고 블랙 벨트를 사용하겠다고 위협했습니다.


나는 그 오타를 너무 많이 만들어서 실제로 고려했습니다.
Joshua

4
오히려 편집기에게 retrun을 자동으로 대체하도록 지시하십시오. 나는 적어도 IRC 클라이언트에게 그러한 해커를 수행했다
Tetha

1
이봐, 내가 그 '건축가'와 함께 일한 적이 있다고 생각합니다. 그는 자신의 자존심을 진정시킬 필요가있을 때 결국 선임 건축가로 재 분류되었습니다.
BIBD

1
입력 할 수 없었고 'rn'뉴스 리더가 시작하고 서버에 연결하는 데 5 분이 걸렸기 때문에 bash에서 'rn'을 'rm'으로 다시 정의했습니다.
Martin Beckett

2
새 터미널을 열거 나 다른 vt로 전환 할 수 없었 killall rn습니까?
Joe D

69

현실 세계? MSVC는 minmax.h에서 매크로, 전화가 maxmin컴파일러 오류를 내가 표준 사용하려는 때마다 원인, std::numeric_limits<T>::max()기능.


2
아, 그렇습니다. 그래서 제가 MS에 특화된 것들 이후에 온전함을 회복시키는
#undef를

3
(std :: numeric_limits <T> :: max) ()로 해결되었습니다. 그래, 꽤 성가시다.
rlbond 2016 년

36
C / C ++-> 전 처리기-> 전 처리기 정의에서 프로젝트 속성에 NOMINMAX를 추가하십시오.
mattnewport 1

18
이러한 매크로는 MS 헤더에 min보다 오래 존재했으며 max는 C ++ 표준 라이브러리에있었습니다.
Richard

4
다른 외부 의존성 중 4 개가 자신의 최소 / 최대 값을 정의 할 때 심하게 괄호로 묶은 매크로에서 잘 작성된 템플릿에 이르기까지 다양한 정도의 짜증을 내며, 그 중 하나를 정의 할 수 없게 만들면 더 나빠집니다 아니면 그렇지 않으면 이것을 건너 뛰십시오 ... 내 책에서 언어는 50 %를 비난합니다.
Roman Starkov

58

파스칼 구문과 프랑스어 키워드의 혼합 :

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }

36
#define zut_alors exit (-1)
MikeyB 2016 년

4
정말 대단하고 웃었습니다. 그래서 이것은 기본적으로 C로 구현 된 현지화 된 프랑스어 버전의 Basic입니까?
Bobby

56

Raymond Chen은 흐름 제어 매크로를 사용하는 것에 대해 정말 좋은 평가 를 받고 있습니다. 그의 가장 좋은 예는 원래 Bourne 쉘 소스 코드와 동일합니다.

ADDRESS alloc(nbytes)
    POS     nbytes;
{
    REG POS rbytes = round(nbytes+BYTESPERWORD,BYTESPERWORD);

    LOOP    INT     c=0;
    REG BLKPTR  p = blokp;
    REG BLKPTR  q;
    REP IF !busy(p)
        THEN    WHILE !busy(q = p->word) DO p->word = q->word OD
        IF ADR(q)-ADR(p) >= rbytes
        THEN    blokp = BLK(ADR(p)+rbytes);
            IF q > blokp
            THEN    blokp->word = p->word;
            FI
            p->word=BLK(Rcheat(blokp)|BUSY);
            return(ADR(p+1));
        FI
        FI
        q = p; p = BLK(Rcheat(p->word)&~BUSY);
    PER p>q ORF (c++)==0 DONE
    addblok(rbytes);
    POOL
}

2
두 가지 점 : 하나,이 페이스트는 원래 들여 쓰기를 엉망으로 만들었습니다. 그리고 두 번째 코드는 열악한 Algol-68 팬의 1970 년대 Unix C입니다. _ 왜 행운의 뻣뻣한 스타일이 기발한 스타일로 자신을 표현할 수 있습니까? 물론 Algol 68을 모르는 사람은 자신의 취향을 넓힐 수있는 기회를 인정하지 않을 수도 있습니다.
다리우스 베이컨

나는 이것이 제안 된 프로그래밍 스타일이 아니라 Steve Bourne에 의한 농담으로 생각 될 수 있다고 생각한다
Martin Beckett

2
나는 if... else... elif... fi그리고 case... esac전에 (본이 sh를 위해 발명 한 언어로) 보았지만 loop... pool은 진짜 보석입니다.
홉스

54

컨테스트 에 전 처리기 매크로를 통해 기능적 언어를 구현하는 chaos-pp 이라는 gem을 제출하고 싶습니다 .

예 중 하나는 전처리기에 의해 500 번째 피보나치 수를 계산하는 것입니다.

전 처리기 이전의 원래 코드는 다음과 같습니다.

int main(void) {
   printf
     ("The 500th Fibonacci number is "
      ORDER_PP(8stringize(8to_lit(8fib(8nat(5,0,0)))))
      ".\n");
   return 0;
}

파일을 전처리하면 다음과 같은 결과가 나타납니다 (약간의 대기 후).

$ cpp -I../inc fibonacci.c 2>/dev/null | tail
  return fib_iter(n, 0, 1);
}
# 63 "fibonacci.c"
int main(void) {
   printf
     ("The 500th Fibonacci number is "
      "139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125"
      ".\n");
   return 0;
}

1
CVS에서 코드를 가져 와서 살펴볼 수 있습니다. 나는 그것을 우연히 발견했을 때 얼마 전에 내 블로그 포스트에 그것에 대한 자세한 내용을 넣었습니다 : bnpcs.blogspot.com/2009/02/… 결과 코드를 디버깅하는 데 문제가 없다면 그것들은 그러한 "언어"에 의해 생성된다), 그것은 C를위한 실제적인 코드 생성기 로서도 사용될 수있을 것이다.
Andrew Y

그냥 컴파일하는 데 시간이
오래

52

Qt에서 직접 :

#define slots   /* */
#define signals /* */

boost :: signals ...와 같은 다른 라이브러리와 상호 작용하는 것이 정말 좋습니다. 예를 들어, Qt에는 다음과 같은 재미있는 코드를 만드는 다른 많은 것들이 있습니다.

class X : public QObject {
   Q_OBJECT
private slots:
   //...
public signals:
   //...
};

그리고 그것은 C ++입니다 ... 그러나 갑자기 :

boost::signals::trackable

더 이상 유효한 C ++이 아닙니다.


5
:) 따라서 다른 라이브러리를 무너 뜨리는 매크로입니다. 즉 더 나은 내가 : 예상보다의
dribeas - 데이비드 로드리게스

38
Qt는 매우 영토이며, 사악 네임 스페이스를 :) 차지하려고 다른 라이브러리를 공격합니다
제레미 Friesner

21
매크로를 사용하여 네임 스페이스의 슬프게도 Qt는 공격 라이브러리 외부
데이비드 로드리게스 - dribeas

7
다행히 부스트 :: signals2이 문제를 해결했다)
bdonlan

9
이 상호 작용이 두려운 경우 Q_SIGNALS 및 Q_SLOTS를 사용하십시오.
Tadeusz A. Kadłubowski

50

Windows.h에는 매크로를 남용하는 많은 기능이 있습니다.


Mr.Valdez는 Windows.h에있는 GetObject 매크로에 짜증이납니다.

GetObject 매크로는 GetObject () 함수를 GetObjectA () 또는 GetObjectW ()로 변경합니다 (빌드가 각각 비 유니 코드 및 유니 코드로 컴파일되는지에 따라 다름)

MrValdez는 GetObject 함수 라인 전에해야 할 일이 싫다

#undef GetObject

Object *GetObject()

대안은 함수 이름을 GetGameObject ()와 같은 다른 이름으로 변경하는 것입니다.


주석에서 jdkoftinoff는 그것을 못 박았습니다 : 문제는 모든 Windows API 함수가 매크로라는 것입니다.

Adam Rosenfield는 windows.h를 포함시키기 전에 NOGDI, WIN32_LEAN_AND_MEAN, NOMINMAX 등을 정의하여 문제를 해결할 수 있다고 언급했습니다.


3
물론 다양한 GDI 기능을 사용할 필요가없는 경우 windows.h를 포함하기 전에 # define'ing NOGDI를 억제 할 수 있습니다. WIN32_LEAN_AND_MEAN, NOMINMAX 등과 같은 다른 매크로는 다른 것들이 정의되거나 포함되는 것을 억제합니다.
Adam Rosenfield

1
GetObject는 매우 일반적인 함수 이름입니다. 아마도 충돌을 피하기 위해 문맥에 더 설명적인 이름을 사용했을 수 있습니다. 그러나 이것은 매우 사악한 매크로 사례입니다.
strager

1
win32에 API 이름을 FooA 및 FooW로 변환하는 모든 매크로가 있다는 것은 상당히 성가신 일입니다. SendMessage에 문제가 있습니다.
i_am_jorf

6
문제는 모든 Windows API 함수가 매크로라는 것입니다. 저를 물린 것은 GetTickCount ()였습니다. 창 밖에서 대부분의 프로그래밍을 수행했기 때문에 창 헤더에서 모든 정의를 찾은 다음 미리 호환성을 확인하기 위해 모두 정의 파일을 만들었습니다.
jdkoftinoff

12
승자가 있다고 생각합니다. 실세계이고, 엄청나게 나쁜 생각이며, 수많은 무고한 프로그래머에게 영향을 미칩니다. Microsoft에서이 보석을 담당하는 사람은 전쟁 범죄자로 간주되어야합니다. 가장 중요한 부분은 Microsoft가 GetObject, SendMessage 또는 CreateWindow와 같이 놀랍도록 일반적인 이름을 사용하는 것에 대해 두 번 생각하지 않았다는 것입니다.
jalf

45
#define return if (std::random(1000) < 2) throw std::exception(); else return

이것은 너무 악하다. 그것은 무작위이며, 항상 다른 장소에서 발생한다는 것을 의미합니다. 반환 진술을 변경합니다. 보통 성명에 따라 자체적으로 실패 할 수있는 코드가 있으며 의심스럽지 않은 무고한 찾고 키워드를 변경합니다. std space에서 예외가 발생하므로 소스를 찾기 위해 소스를 검색하지 않습니다. 훌륭합니다.


4
이 테스트를 방금 테스트했지만 적어도 무작위로 include가 누락되어 기본적으로 컴파일되지 않으며 그다음에 빨간색으로 표시됩니다. 그러나 실수로 포함이있는 경우 상황이 악화됩니다-VC ++ 2010은 여전히 ​​키워드로 표시하고 매크로 확장 툴팁을 표시하지 않으므로 IDE에서 도움을받지 못했습니다 :-/
OregonGhost

나는 그것을 좋아한다! 순수한 천재. "디버그"할 때 얼마나 잘 보이는지 상상해보십시오.
brice

36

동료와 저는 객체 스트리밍 코드 중 일부에서이 두 가지 보석을 발견했습니다. 이러한 매크로는 스트리밍 한 모든 단일 클래스 파일 에서 인스턴스화되었습니다 . 이 끔찍한 코드는 코드베이스 전체에 퍼져있을뿐만 아니라, 원저자에게 접근했을 때, 그는 내부 위키에 7 페이지의 기사를 썼습니다.

말할 것도없이 리팩토링되어 코드 기반에서 더 이상 사용되지 않습니다.

강조 표시된 키워드를 버리지 마십시오. 이것은 모두 매크로입니다

#define DECLARE_MODIFICATION_REQUEST_PACKET( T )                                                \
namespace NameSpace                                                                     \
{                                                                                       \
                                                                                        \
class T##ElementModificationRequestPacket;                                                          \
}                                                                                       \
                                                                                        \
DECLARE_STREAMING_TEMPLATES( IMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase )    \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( NameSpace::ElementModificationRequestPacket<T> )     \
DECLARE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_DECLARE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )      \
                                                                                        \
namespace NameSpace {                                                                   \
class DLLIMPEXP_COMMON T##ModificationRequestPacket : public ElementModificationRequestPacket<T>\
{                                                                                       \
public:                                                                                 \
    T##ModificationRequestPacket( NetBase * pParent )                                   \
    : ElementModificationRequestPacket<T>( pParent ), m_Gen() {}                            \
                                                                                        \
    T##ModificationRequestPacket( NetBase * pParent,                                    \
                            Action          eAction,                                    \
                            const T &   rT )                                            \
    : ElementModificationRequestPacket<T>( pParent, eAction, rT ), m_Gen() {}               \
                                                                                        \
    T##ModificationRequestPacket( const T##ModificationRequestPacket & rhs )                        \
    : ElementModificationRequestPacket<T>( rhs ), m_Gen() {}                                \
                                                                                        \
    virtual                     ~T##ModificationRequestPacket( void ) {}                        \
                                                                                        \
    virtual Uint32          GetPacketTypeID( void ) const                           \
    {                                                                                   \
        return Net::T##_Modification_REQUEST_PACKET;                                        \
    }                                                                                   \
                                                                                        \
    virtual OtherNameSpace::ClassID GetClassID ( void ) const                           \
    {                                                                                   \
        return OtherNameSpace::NetBase::GenerateHeader( OtherNameSpace::ID__LICENSING,  \
                                                         Net::T##_Modification_REQUEST_PACKET );    \
    }                                                                                   \
                                                                                        \
    virtual T##ModificationRequestPacket * Create( void ) const                             \
    { return new T##ModificationRequestPacket( m_pParent ); }                                   \
                                                                                        \
    T##ModificationRequestPacket() {}                                                           \
                                                                                        \
protected:                                                                              \
    OtherNameSpace::ObjectAutogeneration<T##ModificationRequestPacket> m_Gen;                       \
                                                                                        \
    friend class OtherNameSpace::StreamingBase::StreamingClassInfoT<T##ModificationRequestPacket >;                     \
    OtherNameSpace::StreamingBase::Streaming<T##ModificationRequestPacket, ElementModificationRequestPacket<T> >    m_Stream;   \
                                                                                        \
};                                                                                      \
}                                                                                       \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )            \
DLLIMPEXP_COMMON_TEMPLATE_DECLARE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )            \
typedef  ThirdNameSpace::BroadcasterT<const T##ModificationRequestPacket>  T##ModifiedBroadcaster;



#define IMPLEMENT_MODIFICATION_REQUEST_PACKET( T )                                                                  \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( NameSpace::ElementModificationRequestPacket<T> )                         \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::ListenerBase<const NameSpace::T##ModificationRequestPacket> )        \
DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE( ThirdNameSpace::BroadcasterT<const NameSpace::T##ModificationRequestPacket> )        \
INSTANTIATE_STREAMING_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::ElementModificationRequestPacket<T>, OtherNameSpace::NetPacketBase ) \
INSTANTIATE_AUTOGENERATION_TEMPLATES( DLLIMPEXP_COMMON_TEMPLATE_INSTANTIATE, NameSpace::T##ModificationRequestPacket, NameSpace::ElementModificationRequestPacket<T> )

업데이트 (2009 년 12 월 17 일) :

이 끔찍한 매크로 저자에 관한 더 좋은 소식. 8 월 현재,이 괴물에 대한 책임이있는 직원이 해고되었습니다.


3
"디버깅은 처음에 코드를 작성하는 것보다 두 배나 어렵습니다. 따라서 코드를 최대한 영리하게 작성하면 정의에 따라 디버그하기에 충분히 똑똑하지 않습니다." -Brian W. Kernighan
Trevor Boyd Smith

33

나는 다음과 같은 일을 스스로했다.

1992 년쯤에 나는 작은 Lisp 통역사를 썼습니다. 일반적인 C에서는 구현되지 않았지만 해석 된 C와 유사한 언어로 구현되었습니다. 그러나이 C와 같은 언어는 표준 C 프리 프로세서를 사용했습니다.

Lisp 인터프리터는 물론 리스트의 첫 번째 요소를 리턴하기 위해 Lisp에서 사용되는 함수 car 와리 스트 의 나머지를 리턴하는 cdr 을 포함했습니다. 그들은 다음과 같이 구현되었습니다.

LISPID car(LISPID id) {
    CHECK_CONS("car", 1, id);
    return cons_cars[id - CONS_OFFSET];
} /* car */

LISPID cdr(LISPID id) {
    CHECK_CONS("cdr", 1, id);
    return cons_cdrs[id - CONS_OFFSET];
} /* cdr */

(구조체가 없기 때문에 데이터가 배열에 저장되었습니다. CONS_OFFSET 은 상수 1000입니다.)

carcdr 은 Lisp에서 자주 사용되며 짧으며, 구현 언어에서는 함수 호출이 그리 빠르지 않기 때문에 두 개의 Lisp 함수를 매크로로 구현하여 코드를 최적화했습니다.

#define car(id) (CHECK_CONS("car", 1, (id)), cons_cars[(id) - CONS_OFFSET])
#define cdr(id) (CHECK_CONS("car", 1, (id)), cons_cdrs[(id) - CONS_OFFSET])

CHECK_CONS 는 인수가 실제로 목록인지 확인하고, 인터프리터에서 자주 사용되며 짧기 때문에 매크로로도 작성했습니다.

#define CHECK_CONS(fun, pos, arg)   \
    (!IS_CONS(arg) ?        \
        LISP_ERROR("Arg " + pos + " to " + fun +    \
                   " must be a list: " + lispid2string(arg)) : 0)

IS_CONSLISP_ERROR 도 자주 사용되었으므로 매크로로도 만들었습니다.

#define IS_CONS(id) \
    (   intp(id) && (id) >= CONS_OFFSET     \
     && ((id) - CONS_OFFSET) < sizeof(cons_cars))

#define LISP_ERROR(str)     (throw((str) + "\n"))

합리적인 것 같습니까?

그런데 왜이 시스템에서 전체 시스템이 다운 되었습니까?

id2 = car(car(car(car((id1))));

나는 그 짧은 라인이 전처리기에 의해 확장 된 것을 마침내 확인할 때까지 문제를 찾기 위해 오랜 시간을 일했다. 31370 자로 확장되어 명확하게하기 위해 여기에서 선 (502 개)으로 나눕니다.

id2 = ((!(intp( (((!(intp( (((!(intp( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
&& ( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) && ( (((!(intp(
(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) >= 1000 && ((
(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000]))) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (((!(intp( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) && ( (((!(intp( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) >= 1000 && (( (((!(intp(
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && (( (((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000]))) - 1000) < sizeof(cons_cars))
? (throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 &&
(( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to
" + "car" + " must be a list: " + lispid2string( (id1))) + "\n"))
: 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && (
(id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (id1)) && ( (id1)) >= 1000 && ((
(id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to "
+ "car" + " must be a list: " + lispid2string( (id1))) + "\n")) :
0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1)) && ( (id1))
>= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg "
+ 1 + " to " + "car" + " must be a list: " + lispid2string(
(id1))) + "\n")) : 0), cons_cars[(id1) - 1000]))) >= 1000 && ((
(((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1))
- 1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car"
+ " must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])))) + "\n")) : 0), cons_cars[(((!(intp(
(id1)) && ( (id1)) >= 1000 && (( (id1)) - 1000) <
sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" + " must
be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000])) - 1000])) - 1000])))) + "\n")) : 0),
cons_cars[(((!(intp( (((!(intp( (((!(intp( (id1)) && ( (id1)) >=
1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ? (throw(("Arg " +
1 + " to " + "car" + " must be a list: " + lispid2string( (id1)))
+ "\n")) : 0), cons_cars[(id1) - 1000]))) && ( (((!(intp( (id1))
&& ( (id1)) >= 1000 && (( (id1)) - 1000) < sizeof(cons_cars)) ?
(throw(("Arg " + 1 + " to " + "car" + " must be a list: " +
lispid2string( (id1))) + "\n")) : 0), cons_cars[(id1) - 1000])))
>= 1000 && (( (((!(intp( (id1)) && ( (id1)) >= 1000 && (( (id1)) -
1000) < sizeof(cons_cars)) ? (throw(("Arg " + 1 + " to " + "car" +
" must be a list: " + lispid2string( (id1))) + "\n")) : 0),
cons_cars[(id1) - 1000]))) - 1000) < sizeof(cons_cars))

18
I optimized my code by implementing those [..] functions as macros-유명한 마지막 단어 ...
BlueRaja-Danny Pflughoeft

3
Postscript 인터프리터의 초기 버전에서도 비슷한 악용 사례를 범했습니다. 푸시 앤 팝은 매크로가되어야 할 중요한 기능이었습니다 . 그러나 이들 중 하나 이상을 포함하는 표현을 작성하면 정의되지 않은 동작이 발생합니다. 정의되지 않은 동작은 -O3에서 컴파일 할 때만 포착됩니다. 그리고 -O3에서 함수 버전은 어쨌든 인라인되었을 것입니다.
luser droog

29

한때 C 애플리케이션을 유닉스에서 윈도우로 포팅해야했는데, 그 특성은 유죄를 보호하기 위해 명명되지 않은 채 남아있을 것입니다. 이 글을 쓴 사람은 프로덕션 코드 작성에 익숙하지 않은 교수였으며 다른 언어에서 C로 명확하게 왔습니다. 영어가 모국어가 아니 었음에도 불구하고 대부분의 사람들이 모국어로 사용하는 언어는 꽤 잘 사용됩니다.

그의 응용 프로그램은 전처리기를 많이 사용하여 C 언어를 더 잘 이해할 수있는 형식으로 변형 시켰습니다. 그러나 그가 가장 많이 사용한 매크로는 'Thing.h'라는 이름의 헤더 파일에 정의되었으며 다음을 포함합니다.

#define I  Any void_me
#define thou  Any void_thee
#define iam(klas)  klas me = (klas) void_me
#define thouart(klas)  klas thee = (klas) void_thee
#define my  me ->
#define thy  thee ->
#define his  him ->
#define our  my methods ->
#define your  thy methods ->

... 그런 다음 그는 다음과 같은 괴물을 쓰곤했습니다.

void Thing_setName (I, const char *name) {
iam (Thing);
if (name != my name) {
    Melder_free (my name);
    my name = Melder_wcsdup (name);
    }
    our nameChanged (me);
}

void Thing_overrideClass (I, void *klas) {
iam (Thing);
my methods = (Thing_Table)klas;
if (! ((Thing_Table) klas) -> destroy)
    ((Thing_Table) klas) -> _initialize (klas);
}

전체 프로젝트 (~ 60,000 LOC)는 비슷한 스타일로 작성되었습니다-마르코 지옥, 이상한 이름, Olde-English 전문 용어 등. 다행히도 우리는 동일한 알고리즘 수십을 수행하는 OSS 라이브러리를 찾은 후 코드를 버릴 수있었습니다. 몇 배 더 빠릅니다.

( 이 질문에 원래 작성한 답변을 복사하고 편집했습니다 ).


3
나는 소유주와 고풍스러운 영어에 매료되어 있습니다. 물론 코드가 끔찍한 것처럼 보입니다.
다리우스 베이컨

27

내가 경험 한 최악의 상황은 지정된 기술 리더가 라이브러리를 찾지 못한 실행 파일 모음이 포함 된 제품에서 발생했습니다.

대신 여러 Visual Source Safe 폴더에서 공유되는 파일 세트가있었습니다. 그런 다음 각 응용 프로그램마다 약간 다르게 행동해야한다는 것을 깨달았습니다.

여기에 적용 할 수있는 여러 리팩토링 단계가 있습니다.

대신 #ifdefs를 사용했습니다.

   void DisplayLoadError()
   {
   #if defined __TIMETABLE_EDITOR
   MessageBox("Timetable Editor failed to load the correct timetable", MB_ERROR);
   #else if defined __SCHEDULESET_EDITOR
   MessageBox("Schedule Set Editor faied to load the correct Schedule Set", MB_ERROR);
   #else if defined __ROSTER_EDITOR
   MessageBox("Roster Editor failed to load the correct Roster", MB_ERROR);
   #endif
   }

17

네트워크를 통해 전달 된 메시지의 고유 ID를 생성하기 위해 LINE 프리 프로세서 사용 :

NetworkMessages.h

#define MSG_LOGIN  __LINE__
#define MSG_LOGOUT __LINE__
#define MSG_CHAT   __LINE__

이것은 매크로가 매크로가 아닌 솔루션보다 실제로 더 나은 예입니다.

매크로가 아닌 솔루션 클래스에서는 메시지의 ID를 추적하기 위해 함수와 변수를 빌드해야합니다. 개발자는 메시지 ID 추적을 복잡하게 만들거나하지 않을 수 있지만 읽기 및 디버그가 더 쉽습니다.

또한 메시지를 소스에 추가하기 만하면 새 메시지를 쉽게 추가 할 수 있습니다.

이 상황의 단점은 파일을 메시지를 사용하는 모든 코드에 포함시켜야한다는 것입니다. 메시지를 편집 할 때마다 컴파일 시간이 늘어납니다.


8
버전이 서로 호환되지 않을 수 있습니다 (좋지 않습니다!). 열거 형은 어떻게 충분하지 않습니까?
strager

이것과 Enum은 모두 비 호환성 문제가 동일합니다.
MrValdez

17
이제 #defines를 따라 정렬하면 프로토콜이 변경됩니다. 또는 나는 Doxygen 종교를 얻고 모든 메시지 코드와 프로토콜 변경 사항을 문서화합니다. 후자의 변화에 ​​따라 적어도 열거 형이 안정적입니다.
RBerteig

3
@MrValdez는 파일 시작과 관련하여 동일한 행에 정의를 유지하는 것보다 열거 블록을 순서대로 유지하는 것이 덜 제한적입니다.
peterchen

나는 이것이 오래된 게시물이라는 것을 알고 있지만 이것이 효과가 있습니까? #define은 메시지 상수를 LINE으로 바꾼 다음 LINE 만 줄 번호로 확장하므로 다른 줄에서 동일한 상수를 사용할 때마다 (현재 줄 번호로) 변경됩니까?
XzKto

16

한 가지 나쁜 예 :

#ifdef __cplusplus
#define class _vclass
#endif

이것은 classC ++ 컴파일러에 의해 호출되는 멤버 변수를 포함하는 C 구조를 허용합니다 . 이 구성에는 두 개의 헤더가 있습니다. 그들 중 하나는 끝에 '#undef class'를 포함하고 다른 하나는 포함하지 않습니다.


1
이것이 Objective-C가 @class대신 사용 하는 이유 입니다 class.

14

International Obfuscated C Coding Contest의 1 년 동안 전체 프로그램은 다음과 같습니다.

P

proviso를 사용하면 Pmakefile에서 원하는 프로그램으로 정의 할 수 있습니다.

내가 기억 하듯이, 그것은 카테고리 중 하나에서 이겼으며 내년에는 그 스타일의 입장을 허용하지 않는 규칙이 나타났습니다.

(편집 : 6 개월 후 또는 뭔가 ... 나는 이것을 쓸 때 "No IOCCC"가 주요 질문에 있지 않다고 확신합니다 ...)


12

나는 지루했고 Objective-C에서 블록을 가지고 놀고있었습니다 ...

#define Lambda(var, body) [^ id(id (var)) { return (body);} copy]
#define Call(f, arg) ((id(^)(id))(f))(arg)
#define Int(num) [NSNumber numberWithInteger:(num)]
#define Mult(a, b) Int([(a) integerValue] * [(b) integerValue])
#define Add(a, b) Int([(a) integerValue] + [(b) integerValue])
#define Sub1(n) Int([(n) integerValue] - 1)
#define Add1(n) Int([(n) integerValue] + 1)
#define If(cond, thenblock, elseblock) ([(cond) integerValue] ? (thenblock) : (elseblock))
#define Cons(car, cdr_) [[ConsType alloc] initWithCar:(car) cdr:(cdr_)]
#define Car(list) [(list) car]
#define Cdr(list) [(list) cdr]
#define Define(var, value) id var = (value)
#define Nullq(value) Int(value == nil)

다음과 같은 "흥미로운"것들을 허용합니다 :

Define(Y, Lambda(f, Call(Lambda(x, Call(x, x)),
                         Lambda(x, Call(f, Lambda(y, Call(Call(x, x), y)))))));
Define(AlmostTotal, Lambda(f, Lambda(list, If(Nullq(list), Int(0),
                                              Add(Car(list), Call(f, Cdr(list)))))));
Define(Total, Call(Y, AlmostTotal));
Print(Call(Total, Cons(Int(4), Cons(Int(5), Cons(Int(8), nil)))));

(간단하게하기 위해 일부 기능 및 클래스 정의가 표시되지 않음)


"저는 지루했습니다"유명한 개발자의 마지막 말 :)
Richard J. Ross III 1

11

내가 본 최악은 비 사용이었습니다 :-)

누군가가 strcpy를 호출하는 오버 헤드를 원하지 않기 때문에 메소드 내부에 strcpy (지금은 10 년 전 이상이라고 생각합니다) 함수를 작성했습니다.

일본어 문자에서는 작동하지 않으므로 ASCII 또는 유니 코드를 시작할 때 "if"를 추가했습니다. 그 시점에서 코드는 화면 길이가 길었습니다. 캐시 일관성을 없애고 코드 인라인으로 인한 절감액을 지우는 것 같습니다.

코드는 유형에 대해 동일하게 저장되었으므로 매크로를 사용해야합니다.

물론 그들이 쓴 strcpy는 표준 라이브러리에있는 수동 튜닝 어셈블러보다 훨씬 느립니다 ...

물론 그들이 방금 매크로로 모든 것을했다면 strcpy에 대한 호출로 대체 될 수 있습니다 ...

물론 나는 회사를 그만 두었다.


The code was identical save for the types (so should have used a macro).아니요, 그는 템플릿을 사용해야했습니다.
BlueRaja-대니 Pflughoeft

1
그는 내장 된 strcpy를 사용해야했습니다! (그리고 C ++이 아니기 때문에 C 코드가 아니므로 템플릿이 없음) :-P
TofuBeer

조기 최적화는 모든 악의 근원입니다.
Hubert Kario

11

의무

#define FOR  for

#define ONE  1
#define TWO  2
...

누가 알았 겠어?


5
그러나 코드에는 아무런 문자가 없습니다! ;)
Bernard

대체 문자가 아닌 목적 / 의도로 em을 지정해야합니다. 내가 그들이 5 + 5 변수를 만들었다는 소식을 들었다가 나중에 5 + 10이라고 말하는 코드를 가졌다 ... var + 5를하고 var + 10을 받았을 때 실제로 놀란 사람들
Greg Domjan

1
FORTRAN을 통해서만 COBOL에 대해 들어 본 적이 없습니다. 물론 COBOL에는 ZERO, ZEROS 및 ZEROES가 예약어로 있으며 모두 0과 정확히 같은 의미입니다.
David Thornley

"#define ONE 0"보다 훨씬 낫습니다. 킥킥 웃음을 원한다면 웹을 검색하여 0이 아닌 히트 수에 놀라십시오.
reuben

11
#define TRUE 0 // dumbass

몇 년 후 이것을 설명 한 사람은 자신을 설명했습니다 .C 라이브러리 함수의 대부분은 모든 것이 잘되었다는 표시로 0을 반환합니다. 그래서 그는 다음과 같은 코드를 작성할 수 있기를 원했습니다.

if (memcpy(buffer, packet, BUFFER_SIZE) == TRUE) {
; // rape that packet
}

말할 것도없이, 우리 팀 (테스터 또는 개발자)의 누구도 그의 코드를 다시 한번 감히 감히 본 적이 없습니다.


1
0 "모든 것이 정상"이되도록 C 라이브러리 함수를 비난합니다. : P
RCIX

6
왜 같은 것을 선언하지 #define FLAG_SUCCESS 0않습니까?
pyon

11

매크로에 고토가있는 코드를 유지 관리합니다. 따라서 함수에는 끝에 레이블이 있지만 함수 코드에는 표시되지 않습니다. 설상가상으로 매크로는 가로로 스크롤하지 않는 한 일반적으로 화면에서 다른 문장의 끝에 있습니다.

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}

더 나쁜 것은 매크로 goto가 대상 레이블의 정의뿐만 아니라 명령문을 숨길 때 입니다. 완전히 마술.
reuben

나는 그 고통을 겪었지만 매크로는 함수 호출처럼 보였다.
Jonathan Leffler

10
#include <iostream>
#define public_static_void_main(x) int main()
#define System_out_println(x) std::cout << x << std::endl

public_static_void_main(String[] args) {
  System_out_println("Hello World!");
}

3
그리고 런타임을 작성하고 싶었습니다. 내가 얼마나 많은 시간을 절약했는지보세요!
Bernard

4
@Trevor : 예 ... 똑똑한 사람들은 여전히 ​​자바를하고 있습니다. 커버를 위해 실행
마이클 마이어스

이전에 args 뒤에 []와 "#define String int argc, char *"를 넣으면 (슬프게) 컴파일됩니다.
Adam Rosenfield

16
나는 다른 것을 더 좋아합니다. 이것은 몇 가지 매크로로 작성되는 Java에 가까운 것을 보여줍니다. 다른 하나는 엄밀한 매크로와 함수 멤버를 가진 구조체로 작성된 정확한 Java를 보여줍니다. 첫 번째는 값싼 농담이었고 두 번째 것은 정교하고 잘 짜여진 농담이었습니다.
Chris Lutz

10

매직 넘버에 관한 규칙을 이해하지 못한 급우
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1


9

ASA- http : //www.ingber.com/#ASA

정말 고맙게 다운로드해야합니다. 전체 작업 흐름은 매크로에 의해 결정됩니다. 완전히 읽을 수 없습니다. 예로서 -

 if (asa_open == FALSE) {
asa_open = TRUE;
++number_asa_open;
#if ASA_PRINT
if (number_asa_open == 1) {
  /* open the output file */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
#else
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "w");
#endif
  }
#else /* USER_ASA_OUT */
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
#if ASA_SAVE
    ptr_asa_out = fopen (ASA_OUT, "a");
#else
    ptr_asa_out = fopen (ASA_OUT, "w");
#endif
  }
#endif /* USER_ASA_OUT */
} else {
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
  fprintf (ptr_asa_out, "\n\n\t\t number_asa_open = %d\n",
           number_asa_open);
}
#endif /* ASA_PRINT */
} else {
++recursive_asa_open;
#if ASA_PRINT
if (recursive_asa_open == 1) {
  /* open the output file */
#if ASA_SAVE
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (OPTIONS->Asa_Out_File, "a");
  }
#else
  if (!strcmp (ASA_OUT, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {
    ptr_asa_out = fopen (ASA_OUT, "a");
  }
#endif
#else /* ASA_SAVE */
#if USER_ASA_OUT
  if (!strcmp (OPTIONS->Asa_Out_File, "STDOUT")) {
#if INCL_STDOUT
    ptr_asa_out = stdout;
#endif /* INCL_STDOUT */
  } else {

그리고 그것은 옵션을 설정하는 것입니다. 전체 프로그램은 이와 같습니다.


2
세상에 ... 어지러워지는 것 같아
Michael Foukarakis
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.