176

あなたがこれまでに遭遇した最悪の 現実世界のマクロ/プリプロセッサの悪用は何ですか?

本当に面白いのであれば、短いスニペットやストーリーを追加してください。目標は、常に人々に「マクロを使うな」と言うのではなく、何かを教えることです。


ps:以前にマクロを使用したことがあります...しかし、通常、「実際の」ソリューションがあると、最終的にそれらを取り除きます(実際のソリューションがインライン化されているため、マクロに似ている場合でも)。


おまけ:マクロがマクロではないソリューションよりも実際に優れていた例を挙げてください。

関連する質問: C++ マクロが役立つのはいつですか?

4

70 に答える 70

409

記憶から、それは次のように見えました:

#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 ではなく、シンタックス カラーリング機能があります!)。

彼は主にアセンブリ言語で働いていたロシア人プログラマーでした。彼は、メモリが非常に限られているシステムで以前に作業したことがあったため、できるだけ多くのバイトを節約することに熱中していました。「それは衛星用でした。ほんの数バイトしかないので、1 バイトを多くのことに使います。」(ちょっといじって、数値は機械語のバイトを再利用) 衛星の種類を調べてみると、「周回中の衛星。周回するため」しか出てきませんでした。

彼には他にも 2 つの癖がありました。「誰が見ているのかを知るために」モニターの上に取り付けられた凸面鏡と、時折急に椅子から出て腕立て伏せを 10 回すばやく行うことです。彼はこの最後のものを「コンパイラがコードにエラーを発見しました。これは罰です」と説明しました。

于 2009-03-17T03:31:59.757 に答える
274

私の最悪:

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

マルチスレッドの COM ref-counting の問題を追跡するのに 2 日間を費やしました。私が当時働いていた会社については言及しません。

この話の教訓は?わからないことがあれば、ドキュメントを読み、それについて学んでください。ただそれをなくさないでください。

于 2009-03-17T02:38:07.423 に答える
166
#define ever (;;)
for ever { 
   ...
}
于 2009-03-17T02:04:27.910 に答える
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!");
}

課題: より少ない定義と構造体で誰でもそれを実行できますか? ;-)

于 2009-03-17T04:32:05.510 に答える
130
#define private public
于 2009-03-17T02:01:09.757 に答える
107
#define if while

それは誰かにかけられた冗談であり、影響を受けた人には面白くありませんでした

于 2009-03-17T03:36:12.540 に答える
106

恐ろしい:

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

真剣に、Pascal でコーディングしたい場合は、Pascal コンパイラを購入し、美しい C 言語を破壊しないでください。

于 2009-03-17T02:19:20.633 に答える
93

あなたがタイプを知っている「建築家」、非常に謙虚な男は、次のようなものを持っていました:

#define retrun return

彼は速くタイプするのが好きだったからです。脳外科医は、自分より頭のいい人たち(ほとんど全員)に怒鳴りつけ、黒帯を使うと脅すのが好きでした。

于 2009-03-17T02:34:46.777 に答える
69

現実の世界?MSVC の minmax.h にはmaxand と呼ばれるマクロがあり、標準関数minを使用するたびにコンパイラ エラーが発生します。std::numeric_limits<T>::max()

于 2009-03-17T10:36:22.483 に答える
58

Pascal 構文とフランス語のキーワードの組み合わせ:

#define debut {
#define fin }
#define si if(
#define alors ){
#define sinon }else{
#define finsi }
于 2009-03-17T10:22:45.153 に答える
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
}
于 2009-03-17T04:21:08.050 に答える
52

Qtから直接:

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

boost :: signalとして他のライブラリと対話するのは本当に素晴らしいです...ほんの一例として、Qtには次のような面白いコードを作成する他の多くのコードがあります。

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

そしてそれはC++です...しかし突然:

boost::signals::trackable

もはや有効なC++ではありません。

于 2009-03-17T07:35:48.003 に答える
50

Windows.h には、マクロを悪用する関数が多数含まれています。


MrValdez は、Windows.h にある GetObject マクロに悩まされています。

GetObject マクロは、GetObject() 関数を GetObjectA() または GetObjectW() に変更します (ビルドが非 Unicode でコンパイルされているか、Unicode でコンパイルされているかによって異なります)。

MrValdez は、GetObject 関数行の前にやらなければならないことを嫌います

#undef GetObject

Object *GetObject()

別の方法は、関数名を GetGameObject() のような別のものに変更することです


コメントの jdkoftinoff はそれを釘付けにしました: 問題は、すべての Windows API 関数がマクロであることです。

Adam Rosenfield さんは、windows.h をインクルードして問題を取り除く前に、NOGDI、WIN32_LEAN_AND_MEAN、NOMINMAX などを定義することで問題を解決できると述べました。

于 2009-03-17T03:02:45.977 に答える
45
#define return if (std::random(1000) < 2) throw std::exception(); else return

これはとても邪悪です。それはランダムです。つまり、常にさまざまな場所で起動し、return ステートメントを変更します。これには、通常、それ自体で失敗する可能性のあるコードがいくつか含まれています。疑わしいと思われることのない無害に見えるキーワードを変更し、それを使用します。 std スペースからの例外であるため、ソースを検索してソースを見つけようとしません。ただ素晴らしい。

于 2009-10-29T13:26:14.583 に答える
36

同僚と私は、オブジェクト ストリーミング用のコードの一部でこれら 2 つの宝石を見つけました。これらのマクロは、ストリーミングを行うEVERY SINGLEクラス ファイルでインスタンス化されました。この忌まわしいコードが私たちのコード ベース全体に吐き出されているだけでなく、元の作成者にこのことについて問い合わせたところ、彼は社内の wiki に 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月の時点で、この怪物を担当した従業員は解雇されました。

于 2009-06-25T19:18:28.097 に答える
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 で頻繁に使用され、短く、実装言語での関数呼び出しはあまり高速ではなかったため、これら 2 つの 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))
于 2009-10-20T13:08:09.853 に答える
29

私はかつて C アプリケーションを UNIX から Windows に移植しなければなりませんでした。それを書いた人は、生産コードを書くことに慣れていない教授であり、明らかに他の言語から 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) は似たようなスタイルで書かれていました -- マルコ ヘル、変な名前、古い英語の専門用語など。幸運なことに、同じアルゴリズムを何十回も実行する OSS ライブラリを見つけたので、コードを捨てることができました。倍速くなります。

(この質問で最初に作成したこの回答をコピーして編集しました)。

于 2009-09-23T14:21:35.973 に答える
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
   }
于 2009-03-17T05:52:00.000 に答える
17

LINE プリプロセッサを使用して、ネットワークを介して渡されるメッセージの一意の ID を生成します。

NetworkMessages.h

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

これは、マクロが非マクロ ソリューションよりも実際に優れていた例です。

非マクロ ソリューション クラスでは、メッセージの ID を追跡するために関数と変数を作成する必要があります。開発者は、メッセージ ID の追跡を複雑にする場合としない場合がありますが、これは読みやすくデバッグしやすいものです。

さらに、メッセージをソースに追加するだけで、新しいメッセージを簡単に追加できます。

この状況の欠点は、メッセージを使用するすべてのコードにファイルを含める必要があることです。メッセージが編集されるたびに、コンパイル時間が長くなります。

于 2009-03-17T02:42:32.560 に答える
16

かなり悪い例:

#ifdef __cplusplus
#define class _vclass
#endif

これにより、呼び出されるメンバー変数を含む C 構造体をclassC++ コンパイラで処理できます。この構造を含むヘッダーが 2 つあります。そのうちの 1 つは最後に「#undef クラス」も含み、もう 1 つは含みません。

于 2009-03-17T02:20:15.670 に答える
14

International Obfuscated C Coding Contest の 1 年間に、プログラム全体が次のようなエントリがありました。

P

Pただし、makefile で任意のプログラムを定義できます。

私が覚えているように、それはカテゴリーの1つで優勝し、翌年、そのスタイルのエントリーを禁止するルールがポップアップしました.

(編集:6か月後か何か...これを書いたとき、「IOCCCなし」ということは主な質問にはなかったと確信しています...)

于 2009-03-19T13:04:27.767 に答える
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)))));

(簡潔にするために一部の関数とクラスの定義は示していません)

于 2010-03-11T21:34:59.423 に答える
11
#define TRUE 0 // dumbass

これを行った人は、数年後に自分自身を説明しました-ほとんどの(すべてではないにしても)Cライブラリ関数は、すべてがうまくいったことを示すものとして0を返します。それで、彼は次のようなコードを書けるようになりたかったのです。

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

言うまでもなく、私たちのチーム(テスターまたは開発者)の誰も、あえて彼のコードをもう一度見ることはありませんでした。

于 2009-09-18T06:29:13.917 に答える
11

義務

#define FOR  for

#define ONE  1
#define TWO  2
...

誰かわかったね?

于 2009-03-17T02:38:29.590 に答える
11

私が見た最悪のものは不使用でした:-)

誰かがメソッド内に strcpy (そうだったと思います... 10 年以上前だと思います) 関数を書きました (なぜなら、彼らは strcpy を呼び出すオーバーヘッドが欲しくなかったからです... ため息)。

彼らは、日本語の文字では機能しないことに気づき、最初に「if」を追加して、ASCII または Unicode を実行しました。その時点で、コードは約 1 画面分の長さでした...おそらくキャッシュの一貫性が失われ、コードのインライン化のために想定されていた節約が消去されました。

コードはタイプを除いて同一でした (マクロを使用する必要がありました)。

もちろん、彼らが書いた strcpy は、標準ライブラリにある手作業で調整されたアセンブラよりもはるかに遅いものでした...

もちろん、すべてをマクロとして実行していれば、strcpy の呼び出しに置き換えられたはずです...

もちろん会社を辞めました(直接の理由ではありませんが…)

于 2009-03-17T02:03:22.593 に答える
11

マクロに goto があるコードを維持しています。したがって、関数の最後にはラベルがありますが、関数コードには goto が表示されません。さらに悪いことに、水平方向にスクロールしない限り、マクロは通常は画面の外にある他のステートメントの最後にあります。

#define CHECK_ERROR if (!SomeCondition) goto Cleanup

void SomeFunction() 
{ 
    SomeLongFunctionName(ParamOne, ParamTwo, ParamThree, ParamFour); CHECK_ERROR  
    //SomeOtherCode  
    Cleanup:    
   //Cleanup code  
}
于 2009-06-25T19:42:52.277 に答える
10

マジックナンバーに関するルールを理解できなかったクラスメートによる:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1

于 2010-05-03T11:35:11.307 に答える
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!");
}
于 2009-03-17T04:08:47.923 に答える
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 {

などなど

そして、それはオプションを設定するだけです。プログラム全体がそのようなものです。

于 2009-06-25T19:26:36.520 に答える
9

以前コーダーだった「テクニカル マネージャー」は、DOM 解析ルーチンで値をチェックするのは面倒だと考え、次の素晴らしいマクロを C++ プロジェクトに導入しました。NULL

TRYSEGV
CATCHSEGV

内部では、これらはsetjmplongjmp、およびシグナル ハンドラを使用SIGSEGVして、segfault を「キャッチ」する機能をエミュレートしていました。

もちろん、コードが元のTRYSEGVマクロ呼び出しのスコープを終了すると、コード内の何もポイントされたジャンプをリセットしないためコード内の segfault は (現在は無効な)jump_envポインターに戻ります。

コードはそこですぐに停止しますが、プログラム スタックを破棄してデバッグを多かれ少なかれ無意味にする前ではありません。

于 2009-09-18T16:38:05.437 に答える
8

AI Game Programming Wisdomには、マクロを使用して有限状態マシン用のスクリプト言語を作成する章があります。

本とコードは著作権で保護された資料であるため、マクロの詳細を説明するページへのGoogle 本のリンクを次に示します (作成されたスクリプト言語は 324 ページにあります)。

于 2009-03-17T03:13:53.313 に答える
7

この例は気に入っています。マクロを使用して PI の値を近似しています。円が大きいほど、近似の精度が高くなります。

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

もう一つはcプログラム

c

cコンパイルするには、次のように定義する必要があります

-Dc="#include <stdio.h> int main() { char *t =\"Hello World\n\"; while(*t) putc(*t++, stdout); return 0; }"
于 2011-08-11T14:54:49.833 に答える
6

Cのコルーチン(AKAスタックレススレッド):)それは邪悪な策略です。

#define crBegin static int state=0; switch(state) { case 0:
#define crReturn(i,x) do { state=i; return x; case i:; } while (0)
#define crFinish }
int function(void) {
    static int i;
    crBegin;
    for (i = 0; i < 10; i++)
        crReturn(1, i);
    crFinish;
}

int decompressor(void) {
    static int c, len;
    crBegin;
    while (1) {
        c = getchar();
        if (c == EOF)
            break;
        if (c == 0xFF) {
            len = getchar();
            c = getchar();
            while (len--)
            crReturn(c);
        } else
        crReturn(c);
    }
    crReturn(EOF);
    crFinish;
}


void parser(int c) {
    crBegin;
    while (1) {
        /* first char already in c */
        if (c == EOF)
            break;
        if (isalpha(c)) {
            do {
                add_to_token(c);
        crReturn( );
            } while (isalpha(c));
            got_token(WORD);
        }
        add_to_token(c);
        got_token(PUNCT);
    crReturn( );
    }
    crFinish;
}
于 2009-10-23T13:31:57.593 に答える
5
switch (device_id)
{
#ifndef PROD_1
#ifndef PROD_2
#ifdef PROD_3
  case ID_1:
#endif

#ifdef PROD_4

#ifdef PROD_5
  case ID_2:
  case ID_3:
  case ID_4:
#elif defined(PROD_4)
#ifndef PROD_6
  case ID_1:
#endif // PROD_6
  case ID_5:
#endif

  case ID_6:
#endif

#ifdef PROD_7
  #ifndef PROD_8
    case ID_7:
  #endif
#endif

(それほど罪のない人を保護するために名前が変更されました)

まだコードに到達していないことに注意してください。これは、コードの最初の実際のビットに到達するためだけのものです。これは実際には(ほぼ同じ方法ではありませんが)いくつかの関数で発生します。各関数には、最終的に4つのバリエーションしかありません(ほとんどの場合、わずかなバリエーションと独自の#ifdefを使用したコピー/貼り付けです)。

于 2009-06-25T18:42:48.230 に答える
4
#define interface struct

一部のOptima++ヘッダー(Optima ++は、私が使用しなければならなかったWatcom / Powersoft IDEです)。

于 2009-08-07T13:25:03.930 に答える
4

メモリからこれを行う必要がありますが、次のようなものでした: Symbian アプリを作成するためのライブラリを操作します。インクルードする必要のあるヘッダー ファイルには、次の小さな宝石が隠されていました。

// Here come the register defines:
#define C <something>
#define N <something>
<two more single letter defines>

私たちのコードでは、ハードコードされたファイル名を持つファイルの読み込みに失敗しました。ファイルの場所を C ドライブから D ドライブに変更すると、魔法のように機能しました...

于 2010-09-18T22:17:40.930 に答える
3

私が見た中で最悪の事態は、私の現在のプロジェクトで、次のようなケースがたくさんあります。

#if PROGRAMA
     .
     .
    if(...)
    {
     .
     .
     .
#else
    .
     .
    if(...)
    {
     .
     .
     .
#endif
     }

ええ、彼は1回のクローズで2回のオープンを閉じます。

于 2009-11-24T22:44:17.750 に答える
2

私はかつて、マクロを使用して関数をDLLのインポートテーブルにフックするのに役立つこの恐ろしいC++コードをまとめました。


#define ARGLIST(...) __VA_ARGS__

#define CPPTYPELESSARG(typelessParams) thisptr, typelessParams
#define CPPTYPEDARG(typedParams) void* thisptr, typedParams
#define CPPTYPELESSNOARG thisptr
#define CPPTYPEDNOARG void* thisptr

#define CPPHOOKBODY(hookName, params) void *thisptr; \
    __asm { mov thisptr, ecx } \
    return On##hookName ( params );


#define CHOOKBODY(hookName, typelessParams) return On##hookName( typelessParams );

#define CPPHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDARG(typedParams), typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSARG(typelessParams)))

#define CPPHOOKNOARG(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, CPPTYPEDNOARG, typelessParams, \
    typedParams, __thiscall, __stdcall, CPPHOOKBODY(hookName, CPPTYPELESSNOARG))

#define CDECLHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __cdecl, __cdecl, CHOOKBODY(hookName, typelessParams))

#define CDECLFUNC(name, address, returnType, args) \
    typedef returnType (__cdecl *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define CPPFUNC(name, address, returnType, args) \
    typedef returnType (__thiscall *name##Ptr)(void* thisptr, args); \
    name##Ptr name = (name##Ptr) address;

#define STDFUNC(name, address, returnType, args) \
    typedef returnType (__stdcall *name##Ptr)(args); \
    name##Ptr name = (name##Ptr) address;

#define STDHOOK(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams) \
    HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, \
    typedParams, __stdcall, __stdcall, CHOOKBODY(hookName, ARGLIST(typelessParams)))

#define HOOKIMPL(InjectHookRef, importLib, importFunc, hookName, returnType, typedParams, typelessParams, hookParams, fnPtrCall, hookCall, hookBody) \
        typedef returnType (fnPtrCall *##hookName##OrigPtr )( typedParams ); \
        class hookName : public IHook \
        { \
        public: \
            typedef hookName##OrigPtr func_type; \
        private: \
            static void* m_origFunction; \
            static bool m_bModifyImport; \
            static std::string m_lib; \
            static std::string m_importFunc; \
            static std::string m_sHookName; \
            static returnType hookCall hookName##FnHook ( hookParams ) \
            { \
                hookBody \
            } \
            static bool ImplIsModifyImport() { return hookName::m_bModifyImport; } \
            static void ImplSetModifyImport(bool bModify) { hookName::m_bModifyImport = bModify; } \
            static const std::string& ImplGetLibName() { return hookName::m_lib; } \
            static const std::string& ImplGetImportFunctionName() { return hookName::m_importFunc; } \
            static void ImplSetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static void* ImplGetOriginalAddress() { return hookName::m_origFunction; } \
            static returnType On##hookName ( typedParams ); \
            static void* ImplGetNewAddress() { return hookName::##hookName##FnHook; } \
            static const std::string& ImplGetHookName() { return hookName::m_sHookName; } \
        public: \
            hookName() \
            { \
                InjectHookRef.AddHook((IHook*)this); \
                hookName::m_lib = importLib; \
                hookName::m_importFunc = importFunc; \
                hookName::m_sHookName = #hookName; \
                hookName::m_origFunction = NULL; \
                hookName::m_bModifyImport = true; \
            } \
            virtual bool IsModifyImport() const { return hookName::ImplIsModifyImport(); } \
            virtual void SetModifyImport(bool bModify) { hookName::ImplSetModifyImport(bModify); } \
            virtual const std::string& GetHookName() const { return hookName::ImplGetHookName(); } \
            virtual const std::string& GetLibName() const { return hookName::ImplGetLibName(); } \
            virtual const std::string& GetImportFunctionName() const { return hookName::ImplGetImportFunctionName(); } \
            virtual void* GetOriginalAddress() const { return hookName::ImplGetOriginalAddress(); } \
            virtual void* GetNewAddress() const { return hookName::ImplGetNewAddress(); } \
            virtual void SetOriginalAddress(void* fn) { hookName::m_origFunction = fn; } \
            static func_type GetTypedOriginalAddress() { return reinterpret_cast(hookName::m_origFunction); } \
        }; \
        void* hookName::m_origFunction = NULL; \
        bool hookName::m_bModifyImport = false; \
        std::string hookName::m_lib; \
        std::string hookName::m_importFunc; \
        std::string hookName::m_sHookName; \
        static hookName g##hookName##Inst;

これにより、私はこれを行うことができました:

CPPHOOK(gIH, "SimEngine.dll", "?AddEntity@Player@@UAEXPAVEntity@@@Z", PlayerAddEntity, void, void* ent, ent);

/* Called when the engine calls Player::AddEntity(entity) */ void PlayerAddEntity::OnPlayerAddEntity(void *thisptr, void *ent) { unsigned int id = getPlayerID(thisptr);

gIH.GetLog()->Info("Player %d adding entity %s.", 
    getPlayerID(thisptr), getEntityName(ent));

gPlayers[id] = thisptr;

/*if( id == 2 && gPlayers[1] && gPlayers[2] )
    EntitySetOwner::GetTypedOriginalAddress() (ent, gPlayers[1]);*/
//gEnts[ent] = Entity(ent, Vector3f());

PlayerAddEntity::GetTypedOriginalAddress() (thisptr, ent);

}

于 2009-08-07T12:58:01.587 に答える
2

以前の雇用主は、最新の Unix システムにBASIC-PLUSの実装がないことに気付いたので、C プリプロセッサ マクロを使用して再実装しようとしました。

#define IF if(
#define THEN ) {
#define ENDIF }
#define GOTO goto L

...等。

恐ろしい。

于 2010-04-01T10:21:42.320 に答える
2
#define PROCESS_AND_RETURN(X) \
X.process(); \
// Important: Return only after invoking virtual method process() \
return X

「重要」コメントのため、マクロはオブジェクトを返さず、クラッシュします!

于 2011-03-28T10:14:06.650 に答える
2

これは、人気のあるオープン ソース プログラムから取られています。実際、醜い遺産を隠すことで、コードの一部を読みやすくしています。

#define EP_STATUS    CASTLING][(BOARD_FILES-2)
#define HOLDINGS_SET CASTLING][(BOARD_FILES-1)

ここには本当に悪いことは何もないと思います。ただ面白いと思います。

http://git.savannah.gnu.org/cgit/xboard.git/tree/common.h

于 2010-04-06T21:23:39.223 に答える
2

読症の同僚が、#define fasle false.

于 2010-04-06T21:38:12.307 に答える
2

時間の経過とともに私を悩ませ始めた別のものを追加しています:

#define ARRAYSIZE(x) (sizeof(x)/sizeof((x)[0]))

そして、それは彼らがそれを正しく理解した場合です。私は、括弧が存在するかどうかのすべての可能な順列を含むバージョンを見てきました。同じヘッダー ファイルで 2 回定義されているのを見たことがあります。

私の議論は主に Windows に適用されます (ただし、他の OS SDK にも同様のものがあると思います)。ほぼすべての人がプロジェクトのヘッダーでこのマクロを定義する必要性を感じているようですが、その理由はわかりません。

WinNT.h (これは Windows.h に含まれています) は、配列の代わりにポインター型を渡す とコンパイル時にエラーが発生するテンプレート ブードゥーを実行する非常に優れたバージョンを定義します。

もちろん、C プログラムを作成している場合は、上で書いたとおりにフォールバックしますが、SDK がデフォルトで持っているものを理由もなく再定義することはありません。

于 2009-08-20T17:11:14.953 に答える
2

sendmail とその魔法の設定構文を使用するもの

于 2009-08-09T01:47:59.763 に答える
2
#define "CR_LF" '\r'

それはしばらくの間私を混乱させました!

于 2009-10-23T13:43:54.717 に答える
2

Raymond の暴言に関連するのは、次の恐ろしい (もちろん私の意見では) マクロです。

#define CALL_AND_CHECK(func, arg) \
    int result = func(arg);       \
    if(0 != result)               \
    {                             \
        sys.exit(-1);             \
    }                             \

私はマクロの使用にかなり慣れていないため、このマクロを使用しましたが、マクロに渡した関数が失敗することを期待していました。そして、私はそれをバックグラウンドスレッドで行っていたので、アプリ全体が「クラッシュ」する理由に何日も悩まされました。

余談ですが、このマクロが書かれたときに std::tr1::function さえあれば、私は 1 週間前の人生を取り戻すことができたでしょう!

于 2009-03-17T04:34:37.987 に答える
2

C のマクロに初めて出会ったとき、何日も困惑しました。以下は私が直面したものです。C の専門家にとっては完全に理にかなっており、非常に効率的であると思いますが、関数全体が表示されるまで、さまざまなマクロをすべて一緒にカット アンド ペーストすることで何が起こっているのかを正確に理解しようとしました。確かにそれは良い習慣ではありませんか?! 普通の関数を使って何が悪いの?!

#define AST_LIST_MOVE_CURRENT(newhead, field) do { \
typeof ((newhead)->first) __list_cur = __new_prev; \
AST_LIST_REMOVE_CURRENT(field); \
AST_LIST_INSERT_TAIL((newhead), __list_cur, field); \
} while (0) 
于 2009-03-17T02:35:44.260 に答える
2

良いマクロ: (個人的には、この構文を使用するために必要な二重括弧は嫌いですが、引数の数に応じて、vararg マクロ (C99 のみ) または PRINTF_0、PRINTF_1 などのいずれかを好みます)

#ifdef DEBUG
#define PRINTF(x) printf x
#else
#define PRINTF(x)
#endif

非デバッグ ビルドのコード サイズ/実行時間 (最初の時間が 2 番目より長い) を削減します。また、小規模なセキュリティ リスクをもたらす可能性があるデバッグ テキスト文字列の漏洩を防ぎます。

于 2009-03-17T04:30:47.933 に答える
1

最悪の悪用 (そして、私は時々これを行うことに罪を犯しています) は、プリプロセッサをある種のデータ ファイルの置き換えとして使用することです。つまり、次のようになります。

#define FOO_RELATION \  
BAR_TUPLE( A, B, C) \  
BAR_TUPLE( X, Y, Z) \ 

そして別の場所:

#define BAR_TUPLE( p1, p2, p3) if( p1 ) p2 = p3;
FOO_RELATION
#undef BAR_TUPLE

結果は次のようになります。

if( A ) B = C;
if( X ) Y = Z;

このパターンは、あらゆる種類の (ひどい) ことを行うために使用できます... switch ステートメントまたは巨大な if else ブロックの生成、または「実際の」コードとのインターフェース。::cough:: OO 以外のコンテキスト メニュー システム ::cough:: でコンテキスト メニューを生成するためにも使用できます。決して下手なことをしたわけではありません。

編集:括弧の不一致を修正し、例を展開しました

于 2009-03-17T05:33:40.777 に答える
1

ほとんどの場合、マクロの使用はひどいものであることに同意しますが、マクロが役立ついくつかの例を見つけました。

これは実際には素晴らしい私見です.sprintfで似たようなものしか得られないので、リソースの割り当てなどが必要です.さらに、すべての作業はプリプロセッサによって完全に行われます.

// Macro: Stringize
//
//      Converts the parameter into a string
//
#define Stringize( L )          #L


// Macro: MakeString
//
//      Converts the contents of a macro into a string
//
#define MakeString( L )     Stringize(L)


// Macro: $LINE
//
//      Gets the line number as a string
//
#define $LINE                   MakeString( __LINE__ )


// Macro: $FILE_POS
//
//      Gets the current file name and current line number in a format the Visual Studio
//      can interpret and output goto
//
// NOTE: For VS to properly interpret this, it must be at the start of the line (can only have whitespace before)
//
#define $FILE_POS               __FILE__ "(" $LINE ") : "

私が使いたくないが、非常に便利だと思うもう1つの方法は、基本的に可変数のテンプレートパラメーターを持つテンプレートをすばやく生成できるようにすることです。

#define TEMPLATE_DEFS    typename ReturnType
#define TEMPLATE_DECL   ReturnType
#define FUNCTION_PARAMS void
#define FUNCTION_PASS   
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer0
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1
#define TEMPLATE_DECL   ReturnType, P1
#define FUNCTION_PARAMS P1 param1
#define FUNCTION_PASS   param1
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer1
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2
#define TEMPLATE_DECL   ReturnType, P1, P2
#define FUNCTION_PARAMS P1 param1, P2 param2
#define FUNCTION_PASS   param1, param2
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer2
#include "Callback.inl"

#define TEMPLATE_DEFS   typename ReturnType, typename P1, typename P2, typename P3
#define TEMPLATE_DECL   ReturnType, P1, P2, P3
#define FUNCTION_PARAMS P1 param1, P2 param2, P3 param3
#define FUNCTION_PASS   param1, param2, param3
#define GENERIC_CALLBACK_DECL_NAME      CallbackSafePointer3
#include "Callback.inl"

// and so on...

これにより、「Callback.inl」を読むのはちょっと恐ろしいことになりますが、同じコードを異なる数の引数で書き直すことは完全になくなります。また、"Callback.inl" はファイルの末尾にあるすべてのマクロを #undef することにも言及しておく必要があります。したがって、マクロ自体は他のコードに干渉することはなく、"Callback.inl" の記述が少し難しくなります。 (ただし、読み取りとデバッグはそれほど難しくありません)

于 2009-08-07T00:56:26.283 に答える
1

宣言で見つかり、多くの混乱を招きました:

NON_ZERO_BYTE         Fixed(8)  Constant('79'X),

後で見つけた:

IF WORK_AREA(INDEX) = ZERO_BYTE THEN  /* found zero byte */ 
   WORK_AREA(INDEX) = NON_ZERO_BYTE ; /* reset to nonzero*/
于 2009-03-17T04:53:27.627 に答える
1

約 10 年前に使用した ASIC のドライバー コードには、次のようなセクションが多数ありました。

int foo(state_t *state) {
    int a, b, rval;

    $
    if (state->thing == whatever) {
        $
        do_whatever(state);
    }
    // more code

    $
    return rval;
}

多くの頭を悩ませた後、最終的に定義を見つけました。

#if DEBUG
#define $ dolog("%s %d", __FILE__, __LINE__);
#else
#define $
#endif

これを使用するソース ファイルにはインクルード ファイルが含まれていなかったため、これを見つけるのは困難でした。top.c次のようなソースファイルと呼ばれるファイルがありました。

#include <namechanged.h>
#include <foo.c>
#include <bar.c>
#include <baz.c>

案の定、これが Makefile で参照されている唯一のファイルでした。何かを変更するたびに、すべてを再コンパイルする必要がありました。これは「コードを高速化するため」でした。

于 2011-04-14T13:43:17.273 に答える
1

Cマクロじゃないけど…

何年も前に、オリジナルの Transport Tycoon を PC から Mac に移植するという楽しい仕事がありました。PC バージョンは完全にアセンブラで書かれていたので、ソース コード全体を調べて、最初に「PC」C コードに移植し、次にそれを Mac に移植する必要がありました。ほとんどのコードは問題なく、オブジェクト指向の場所もありました。しかし、世界のレンダリング システムは信じられないほどでした。ゲームをプレイしていない人は、世界を 3 つのズーム レベルのいずれかで表示できます。このためのコードは、次の行に沿ったものでした。

macro DrawMacro <list of arguments>
   a couple of thousand lines of assembler with loads of conditionals
   based on the macro arguments

DrawZoomLevel1:
   DrawMacro <list of magic numbers>

DrawZoomLevel2:
   DrawMacro <list of more magic numbers>

DrawZoomLevel3:
   DrawMacro <list of even more magic numbers>

マクロをアセンブルしようとするとアセンブラがクラッシュするため、MASM の少し古いバージョンを使用していたに違いありません。

スキズ

于 2009-09-23T14:36:50.090 に答える
1

マクロを本当に愛する大きなプロジェクトをデバッグしようとすると、他のマクロを呼び出す他のマクロなどを呼び出すマクロがたくさんあります (5-10 レベルのマクロはそれほど珍しくありませんでした)。

そして、多くの #ifdef this マクロと #else that マクロを追加して、コードに従えば、さまざまなパスのツリーのように進むことができます。

唯一の解決策は、ほとんどの場合、代わりにそれをプリコンパイルして読み取ることでした....

于 2009-03-17T06:03:10.037 に答える
1

クリンゴン語で効果的にプログラミングできるように、すべての C キーワードをエイリアスするマクロ パッケージを見たことがあります。そうです、クリンゴン様。残念ながら、このプロジェクトは数年前に放棄され、取り下げられました。

于 2010-03-11T22:08:59.947 に答える
1

当時、マクロを引数として別のマクロに「渡す」ことは良い考えのように思えました。(複数の場所で値のリストを定義するという考えに耐えられませんでした。)ここのコードは不自然です(そしてあまりやる気がありません)が、アイデアを提供します:

#define ENUM_COLORS(CallbackMacro) \
    CallbackMacro(RED)   \
    CallbackMacro(GREEN) \
    CallbackMacro(BLUE)  \
    // ...

#define DEFINE_COLOR_TYPE_CALLBACK(Color) \
    Color,

enum MyColorType {
    ENUM_COLORS(DEFINE_COLOR_TYPE_CALLBACK)
};

void RegisterAllKnownColors(void)
{
#define REGISTER_COLOR_CALLBACK(Color) \
    RegisterColor(Color, #Color);

    ENUM_COLORS(REGISTER_COLOR_CALLBACK)
}

void RegisterColor(MyColorType Color, char *ColorName)
{
    // ...
}
于 2009-09-18T03:36:17.220 に答える
1

プリプロセッサの「創造的な」使用の別の部分ですが、これはメカニズム (信じられないほどありふれたもの) よりも使用されている用語の方が多くなっています。

/***********************************************************************
 * OS2 and PCDOS share a lot of common codes.  However, sometimes
 * OS2 needs codes similar to those of UNIX.  NOTPCDOS is used in these
 * situations
 */

#ifdef OS2
#define PCDOS
#define NOTPCDOS
#else /* OS2 */
#ifndef PCDOS
#define NOTPCDOS
#endif /* PCDOS */
#endif /* OS2 */

本物のコード - 削除したと思っていましたが、削除されていないようです。私はいくつかの一時的なブランチでそれを行ったに違いなく、それをメインコードにチェックインする許可を得ていませんでした. 「やることリスト」にもう一つ。

于 2009-03-17T03:22:06.117 に答える
1

BSD カーネルの NFS コードは、マクロ間で goto を使用します。それはまだ使用されており、コードは実際に機能します。私はそれを片付けようとした人を何人か知っていますが、しばらくすると全員があきらめました。

ここで見ることができます: http://www.openbsd.org/cgi-bin/cvsweb/src/sys/nfs/nfsm_subs.h?rev=1.43

于 2010-02-02T14:50:30.117 に答える
0
#define protected private

良いアイデアのように思えることもありますが、必要に応じて、とにかく文字列を置換する必要があります。保護されていることはかなり悪です。子孫への内部アクセスを許可することは、アイテムを公開することよりもはるかに優れています...

于 2009-03-19T15:22:26.257 に答える
0

Boost Preprocessor は好きではありません。私は一度それを使用する方法を理解しようとしました(とにかくプロジェクトにBoostがありました.

マクロのループに相当するアイデアは気に入りましたが、あまりにも多すぎました。

于 2009-09-18T03:05:30.923 に答える
0

トークン連結演算子を使用するマクロ##

私の同僚が一緒に仕事をする喜びを感じている人を見ました。彼らは、文字列インターンのカスタム実装を作成しようとしたため、(もちろん) 適切に機能しない膨大な数のマクロを使用して文字列を再実装しました。それが何をしたのかを理解しようとすると、##散らばっているすべての のせいで目が爆発しました。

于 2009-06-25T19:48:11.190 に答える
0
#undef near
#undef far

私がゲーム プログラミングを始めたばかりの頃、私が書いたゲームであるカメラ クラスのフラスタムを書いていましたが、コードに非常に奇妙なエラーがありました。

Microsoft は、windows.h に near と far の #defines をいくつか持っていたため、それらを含む行で _near および _far 変数がエラーになったことが判明しました。問題を追跡するのは非常に困難でした (当時私は初心者でした)。また、プロジェクト全体で 4 行しか存在しなかったため、すぐにはわかりませんでした。

于 2009-09-18T16:45:45.657 に答える
0

ヘッダー ファイルを大きなマクロとして使用しました。

// compile-time-caller.h
#define param1 ...
#define param2 ...
#include "killer-header.h"

// killer-header.h
// uses param1 and param2

また、再帰ヘッダー ファイルも作成しました。

// compile-time-caller.h
#define param1 ...
#define param2 ...
#include "killer-header.h"

// killer-header.h"
#if ... // conditional taking param1 and param2 as parameters
#define temp1 param1
#define temp2 param2
#define param1 ... // expression taking temp1 and temp2 as parameters
#define param2 ... // expression taking temp1 and temp2 as parameters
#include "killer-header.h"
// some actual code
#else
// more actual code
#endif
于 2009-07-01T14:19:49.430 に答える
0

私はlibtidyでそれを見つけました:

 /* Internal symbols are prefixed to avoid clashes with other libraries */
 #define TYDYAPPEND(str1,str2) str1##str2
 #define TY_(str) TYDYAPPEND(prvTidy,str)

 TY_(DocParseStream)(bar,foo);

問題は、Visual Studio 2005 と、おそらく他の IDEgo to definitiongo to declaration機能が目的の宣言を見つけるだけで#define TY_(...)、目的のDocParseStream宣言を見つけないことです。

こっちの方が安全かも。

関数ごとに接頭辞を付けて、マクロを呼び出さないようにすべきだと思います..コードが乱雑になっています..しかし、おそらく私はそれについて間違っています。どう思いますか..?

Ps: ほとんどすべての内部関数 const およびその他は、これを使用して前置されているようです..私の同僚は、それが通常であると私に言った..wtf? 多分私は何かを逃した。

于 2009-10-20T11:54:25.913 に答える
0

優しくしてください。例外を一般的にキャプチャする唯一の方法としてこれを書きました。

これを使用して、パブリック インターフェイス関数から例外が伝播するのをキャプチャして停止します...

/// Catch all generic exceptions and log appropriately.
/// Logger is insulated from throwing, so this is a NO THROW operation.
#define CatchAll( msg ) \
    catch( const Poco::Exception &e )   \
    {   \
        try{ LogCritical( Logs.System(), std::string( e.displayText() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch( const std::exception &e )    \
    {   \
        try{LogCritical( Logs.System(), std::string( e.what() ).append( msg ) );}catch(...){assert(0);} \
    }   \
    catch(...)  \
    {   \
        try{ LogCritical( Logs.System(), std::string( "Exception caught in " __FUNCTION__ ". " ).append( msg ) );}catch(...){assert(0);}    \
    }   

私は複雑さが嫌いで、マクロも嫌いですが、一般的なキャッチ ハンドラーをどのように「実行」しますか? これはすべてを意味するものではありません。これは、従来のパブリック関数を隔離し、関数が境界を越えて呼び出されていることがわかっている場合に、少なくともある程度の保護を迅速に追加するための私の汎用キャッチ ハンドラーです。 C++ 例外がスローされました (ようこそ、JNI)。

それで、それはあなたを逃げたり隠したりしますか、それともこのようなことをする唯一の方法ですか?

基本的...

try{
// some block of code capable of throwing
}
CatchAll()
于 2011-05-18T18:59:02.043 に答える
-1

トークン連結演算子 ## を使用するもの。私は、これが C++ の疑似テンプレート システムやその他の恐ろしいものを一緒にハッキングするのに使用されているのを見てきました。これを使用する上で最悪なのは、エラー メッセージが信じられないほど不可解になることです。

しかし、私はそれの良い使い方を見てきました。定義済みの監視クラスとクラス名から継承し、各コンポーネントの監視に使用されるシングルトン クラスに自動登録するクラスをコンパイル時に生成するマクロ #MONITOR_COMPONENT(classname) がありました。

うまくいきましたか?はい、それはそれを行うための最も良い方法でした..おそらくそうではありません.

于 2009-03-17T04:29:56.500 に答える