你遇到过的最糟糕的现实宏/预处理器滥用情况是什么?

什么是 最糟糕的 现实世界宏/预处理器滥用你曾经遇到过(请不要做作的 IOCCC 答案 * 哈哈 *) ?

请添加一个简短的片段或故事,如果它是真正有趣的。我们的目标是教授一些东西,而不是总是告诉人们“永远不要使用宏”。


P.S. : 我以前使用过宏... ... 但通常当我有一个“真正的”解决方案时,我最终会去掉它们(即使真正的解决方案是内联的,所以它变得类似于宏)。


附加说明: 举个例子,说明宏实际上比非宏解决方案更好。

相关问题: 什么时候 C + + 宏是有益的?

127426 次浏览
#define private public

我看到的最糟糕的一个是没有使用: -)

有人在一个方法内写了一个 strcpy 函数(我想就是这样... ... 到现在已经超过10年了)(因为他们不想要调用 strcpy 的开销... ... 唉)。

他们暗示这对日文字符不起作用,所以他们在开始处理 ASCII 或 Unicode 时加了一个“如果”。那时代码大约有一个屏幕那么长... ... 可能会扼杀缓存的一致性,并且抹去他为代码内联而预期的节省。

除了类型之外,代码是相同的(所以应该使用宏)。

当然,他们编写的程序比标准库中的手动调优汇编程序慢得多。

当然,如果他们只是把它作为一个宏来完成,那么它可能会被一个 strcpy 调用所替代... ..。

我当然辞职了(不是直接因为这个... ...)

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

丑陋的:

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

说真的,如果你想用 Pascal 编写代码,买一个 Pascal 编译器,不要破坏漂亮的 C 语言。

一个相当糟糕的例子:

#ifdef __cplusplus
#define class _vclass
#endif

这允许 C + + 编译器处理包含名为 class的成员变量的 C 结构。有两个包含此结构的头; 其中一个在结尾也包含“ # undef 类”,另一个则不包含。

一个“建筑师”,非常谦虚的家伙,你知道的类型,有以下几点:

#define retrun return

因为他喜欢快速打字。这位脑外科医生过去喜欢对比他聪明的人(几乎是所有人)大喊大叫,并威胁要对他们使用黑带。

当我第一次遇到 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)

最糟糕的是:

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

我花了两天的时间追踪一些多线程 COM 引用计数问题,因为一些白痴把这个放在一个头文件。我不会提及我当时工作的公司。

这个故事的寓意是什么?如果您不理解某些内容,请阅读文档并了解相关内容。不要让它消失。

义务

#define FOR  for

还有

#define ONE  1
#define TWO  2
...

谁知道呢?

使用 LINE 预处理器为通过网络传递的消息生成唯一 ID:

NetworkMessages.h


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

这是一个宏观解决方案比非宏观解决方案更好的例子:

在非宏解决方案类中,必须构建函数和变量来跟踪消息的 ID。开发人员可能会使消息 ID 跟踪变得复杂,也可能不会,但这更容易阅读和调试。

此外,只需将消息添加到源中,就可以更容易地添加新消息。

这种情况的缺点是文件必须包含在所有使用消息的代码中。每当编辑消息时,编译时间都会增加。

H 有很多滥用宏的函数。


Valdez 对 Windows.h 中的 GetObject 宏感到恼火

GetObject 宏将 GetObject ()函数更改为 GetObjectA ()或 GetObjectW ()(取决于构建是否分别以非 unicode 和 unicode 编译)

Valdez 先生讨厌在 GetObject 函数行之前必须做的事情

#undef GetObject


Object *GetObject()

另一种方法是将函数名更改为类似 GetGameObject ()的其他名称


Jdkoftinoff 在注释中已经说明了这一点: 问题是所有的 windows API 函数都是宏。

Adamrosenfield 提到,这些问题可以通过定义 NOGDI、 wIN32 _ LEAN _ AND _ MEAN、 NOMINMAX 等来解决,然后再包括 windows.h 来消除这些问题。

AI 游戏编程智慧 有一章中宏被用来为有限状态机创建 脚本语言

因为这本书和代码是受版权保护的材料,这里有一个 谷歌图书链接到详细描述宏的页面(最终的脚本语言可以在第324页找到。)

预处理器的另一个“创造性”用法,尽管它更多的是用于术语而不是机械学(这是令人难以置信的世俗) :

/***********************************************************************
* 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 */

真正的密码,我以为我删掉了,但显然没有。我一定是在某个临时分支中做了这件事,没有获得将其检查回主代码的许可。“待办事项”列表中的另一项。

从记忆中看,它是这样的:

#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,它有语法着色!)

他是一名俄罗斯程序员,大部分时间都在从事汇编语言的工作。他热衷于尽可能多地节省字节,因为他以前工作在内存非常有限的系统上。“这是为了卫星。只有很少的字节,所以我们用每个字节做很多事情。”当我试图找出什么类型的卫星时,我只能得到“轨道卫星”的指令。进入轨道

他还有另外两个怪癖: 一面凸面镜安装在他的显示器上方,上面写着“知道谁在看着我们”; 另一个怪癖是偶尔从椅子上突然离开,做一个快速的十个俯卧撑。他将最后一个解释为“编译器在代码中发现错误。这是惩罚。”。

#define if while

这是对某人开的玩笑,受影响的人并不觉得好笑

#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!");
}

Raymond Chen 有一个 反对使用流程控制宏的大声疾呼:

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
}

任何使用令牌连接操作符 # # 的内容。 我曾经见过用 C + + 和其他可怕的东西来破解模板系统。使用它最糟糕的事情是您的错误消息变得非常神秘。

不过,我看到了它的一个好用处,那就是有一个宏 # MONITOR _ COMPONENT (classname) 在编译时生成的类将继承自预定义的监视器类和类名,并且将自动注册用于监视每个组件的单例类。

成功了吗? 是的,这是最好的方式吗? 可能不是。

好的宏: (尽管我个人不喜欢使用这种语法所需的双括号; 我更喜欢 vararg 宏(仅限于 C99)或类似 PRINTF _ 0、 PRINTF _ 1等等的宏,这取决于参数的数量)

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

减少非调试版本的代码大小/执行时间(前者大于后者) ; 还可以防止泄漏可能构成较小安全风险的调试文本字符串

#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!");
}

挑战: 有人能用更少的定义和结构做到吗? ; -)

与雷蒙德的咆哮相关的是以下可怕的宏观(当然,在我看来) :

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

对于使用宏的实践,我是相当新的,并且使用了这个宏,但是我传递给它的函数 意料之中失败了。而且我是在一个后台线程中完成的,所以我困惑了好几天,为什么我的整个应用程序都“崩溃”了。

顺便说一句,如果在编写这个宏的时候只有 std: : tr1: : 函数,那么我就可以有一个星期的生命了!

在声明中发现,令人困惑的是:

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*/

最糟糕的滥用(我偶尔也这样做)是使用预处理器作为某种数据文件的替代品,比如:

#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: : 。我从没做过这么逊的事。

编辑: 固定不匹配括号和扩展示例

我遇到过的最糟糕的情况是,在一个包含一套可执行文件的产品中,指定的技术负责人还没有搞清楚库的问题。

相反,他有一组在多个 VisualSourceSafe 文件夹中共享的文件。 然后他意识到,它们需要在每个应用程序中表现略有不同。

您可以在这里应用许多重构步骤。

相反,他使用了 # 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
}

尝试调试真正喜欢宏的大项目, 还有很多宏调用其他宏调用其他宏等等。 (5-10级的宏并不罕见)

然后加上大量的 # ifdef 这个宏 # else 那个宏, 所以如果你遵循代码,它就像一棵不同路径的树,它可以走。

唯一的解决方案是在大多数情况下预编译并读取... ..。

直接来自 Qt:

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

真的很高兴与其他库进行交互,比如记号加载... ... 举个例子,Qt 中还有很多其他代码可以创建看起来很有趣的代码,比如:

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

那就是 C + + ... 但突然之间:

boost::signals::trackable

不再是有效的 C + + 了。

Pascal 语法和法语关键词的混合体:

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

现实世界?MSVC 在 minmax.h 中有宏,称为 maxmin,每次我打算使用标准的 std::numeric_limits<T>::max()函数时,它都会导致编译器错误。

在一年的国际混淆 C 编码比赛中,有一个项目的整个程序是:

P

前提是您可以在 makefile 中定义 P,使其成为您想要的任何程序。

据我回忆,它在其中一个类别中获胜,第二年就出现了一条规则,不允许这种方式进入。

(编辑: 六个月后或什么时候... ... 我确信当我写这篇文章时,主要问题中没有“禁止 IOCCC”的内容... ...)

#define protected private

有时候看起来是个好主意,但是如果需要的话,你也许应该直接使用字符串替换。受保护是相当邪恶的,允许内部访问后代并不比仅仅公开物品好多少..。

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种可能的变体(也主要是带有轻微变体的复制/粘贴和它们自己的 # ifdefs)。

我和一个同事在我们的一些对象流代码中发现了这两个亮点。这些宏在进行流处理的 每一个人类文件中被实例化。不仅仅是这些可怕的代码遍布我们的代码库,当我们找到原作者时,他在我们的内部维基上写了一篇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月,负责这个怪物的员工被解雇了。

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 {

等等。

这只是设置选项,整个程序就是这样的。

我维护宏中包含 gotos 的代码。所以一个函数在末尾有一个标签,但是在函数代码中没有可见的 goto。更糟糕的是,宏位于其他语句的末尾,除非水平滚动,否则通常不会出现在屏幕上。

#define CHECK_ERROR if (!SomeCondition) goto Cleanup


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

任何使用令牌连接操作符 ##的宏。

我见过一个我的同事有幸与之共事的人。他们试图制作一个字符串实习的自定义实现,所以他们重新实现字符串使用大量的宏(当然)不能正常工作。试图弄清楚它到底做了什么,我的眼睛爆炸了,因为所有的 ##的分散。

在朗讯,我曾经看过 Steve Bourne 原始 Unix shell 的源代码,发现他使用 C 预处理器使 C 看起来像 帕斯卡还是 Algol。处理 if 语句的部分如下:

#define IF   if (
#define THEN ) {
#define ELSE } else {
#define ELIF } else if (
#define FI   ; }

我的一个朋友告诉我,他在上世纪90年代中期对它进行了一些维护,但它仍然是一样的。(我们可以从代码库固有的保守性中得到一个教训。)

当然,史蒂夫在早期是作为一个实验这样做的,我敢肯定,如果他后来写它会有第二个想法。

更新: 根据维基百科的 《谍影重重》的文章,宏赋予了它 Algol 68的风味。完整的宏集合来了!他们显然影响了国际C语言混乱代码大赛的创始人。

我使用头文件作为宏:

// 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

我想为竞赛提交一个名为 一团糟的 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;
}

我同意宏在大多数情况下使用起来很糟糕,但是我已经找到了一些有用的例子。

恕我直言,这个实际上非常出色,因为您只能使用 sprintf 获得类似的内容,而 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 ") : "

我不喜欢使用的另一个方法是这样做,它非常有用,基本上允许我快速生成具有可变数量的模板参数的模板

#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”# 取消了文件末尾所有宏的定义,因此,宏本身不会干扰任何其他代码,它只是让“ Callback.inl”更难写(不过读取和调试并不太难)

我曾经整合了这个可怕的 C + + 代码,它使用宏来帮助将函数挂钩到 DLL 的导入表中。


#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) ;

/* 在引擎调用 Player: : AddEntity (tity) */时调用 OnPlayerAddEntity (void * thisptr,void * ent) { Unsignedint 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);

}

#define interface struct

在一些 Optima + + 头文件中(Optima + + 是/曾经是我必须使用的 Watcom/Powersoft IDE)。

任何使用 sendmail 及其神奇配置语法的东西

随着时间的推移,我又增加了一个让我烦恼的问题:

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

如果他们答对了的话,我已经看到了所有可能的括号排列的版本,不管是否存在。我在同一个头文件中看到它被定义了两次。

我的观点主要适用于 Windows (尽管我假设其他 OS SDK 也有类似的东西) ,几乎每个人似乎都觉得有必要在他们项目的标题中定义这个宏,我不明白为什么。

WinNTh (包含在 Windows.h 中)定义了一个非常好的版本,如果您传递的是指针类型而不是数组,那么它会执行一些模板巫术,从而导致 编译时错误。

当然,如果您正在构建一个 C 程序,那么它就回到了我上面所写的内容,但是我仍然不会无缘无故地重新定义 SDK 默认的东西。

我不喜欢升压预处理器的东西。我曾经试图弄清楚如何使用它(我们在项目中有 Boost...) ,但就我所知,使用它会使我的错误消息如此不可读,不值得这样做。

我喜欢循环宏的等价概念,但它实在太多了。

当时,将一个宏作为参数“传递”到另一个宏似乎是个好主意。(我只是无法忍受在多个地方定义一个值列表的想法。)这里的代码是人为设计的(并不是很激励人心) ,但是给出了一个想法:

#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)
{
// ...
}
#define unless(cond) if(!cond)
#define until(cond) while(!cond)

用途:

unless( ptr == NULL)
ptr->foo();
#define TRUE 0 // dumbass

做这件事的人几年后解释道——大多数(如果不是全部的话) C 库函数返回0表示一切进展顺利。因此,他希望能够编写这样的代码:

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

不用说,我们团队中的任何人(测试人员或开发人员)都不敢再看他的代码。

#define FLASE FALSE

这个程序员打字很差,这是他最常犯的错误。

一位“技术经理”曾经是一名编码员,他将以下 太棒了宏引入到我们的 C + + 项目中,因为他认为在 DOM 解析例程中检查 NULL值太麻烦了:

TRYSEGV
CATCHSEGV

在幕后,它们使用 setjmplongjmpSIGSEGV信号处理器来模拟“捕获”一个 Segfault 的能力。

当然,一旦代码已经退出了原始 TRYSEGV宏调用的范围,代码中的任何内容都不会重置跳转指针,因此代码中的 任何 Segfault 将返回到(现在无效的) jump_env指针。

代码会立即死在那里,但是在此之前会销毁程序堆栈并使调试多少变得毫无意义。

#undef near
#undef far

当我刚接触游戏编程的时候,我正在为一个摄像头类编写一个插件,这是我编写的一个游戏,我的代码中出现了一些非常奇怪的错误。

事实证明,微软在 windows.h 中有一些关于“接近”和“远”的 # 定义,这导致我的“接近”和“远”变量在包含它们的行上出错。这是非常困难的追踪问题,因为(我当时是一个新手) ,他们只存在于整个项目的四行,所以我没有马上意识到。

我曾经不得不将一个 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)都是以类似的风格编写的—— Marco hell、怪异的名字、古老的英语术语等等。幸运的是,我们能够扔掉代码,因为我发现一个 OSS 库,执行相同的算法快了几十倍。

(我已经复制和编辑了这个答案,这是我最初制作的 在这个问题上)。

不是 C 宏,但是..。

许多年前,我有一项有趣的任务,就是将原始运输大亨从个人电脑移植到 Mac 电脑上。PC 版本完全是用汇编语言编写的,所以我们必须遍历整个源代码,并首先将其移植到“ PC”C 代码,然后再将其移植到 Mac。大部分代码都是可以的,甚至在某些地方面向对象也是可以的。然而,世界渲染系统是令人难以置信的。对于任何没有玩过这个游戏的人来说,这个世界可以在三个变焦级别中的一个看到。其代码大致如下:

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 版本,因为当我们试图组装它的时候,宏会使汇编程序崩溃。

斯基兹

我在杂乱无章中找到的:

 /* 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);

问题是,可视化工作室2005年,也许其他的 IDE go to definitiongo to declaration功能只找到 #define TY_(...),而不是想要的 DocParseStream声明。

也许这样更安全。

我认为他们应该为每个函数设置一个前缀,而不是调用宏来完成这项工作。.把代码弄乱了。.但也许我错了。 你觉得呢?

P: 似乎几乎所有的内部函数 const 和其他函数都使用这个前缀。.我的同事刚刚告诉我,这是惯例。.卧槽?也许我遗漏了什么。

我自己做了下面的事情,我想我从中学到了一些东西。

大约在1992年,我写了一个小的 Lisp 解释器,它没有在正常情况下实现 不过,这种类似 C 的语言使用的是标准的 C 预处理器。

Lisp 解释器当然包含函数 ,即 用于返回列表中的第一个元素,以及返回 返回列表的其余部分。它们的实现方式如下:

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。)

Car Cdr在 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 _ CONS 错误也经常使用,所以我把它们也做成了宏:

#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))

Coroutines (又名堆栈线程)在 C:)这是邪恶的诡计。

#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;
}
#define "CR_LF" '\r'

这把我搞糊涂了!

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

这太邪恶了。它是随机的,这意味着它总是在不同的地方发射,它改变返回语句,这通常有一些代码在它上面,可能会自己失败,它改变无害的外观关键字,你永远不会怀疑,它使用异常从标准空间,所以你不会尝试搜索,通过你的来源,找到它的来源。太有才了。

我所见过的最糟糕的情况是在我目前的项目中有很多这样的案例:

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

是的,他关闭2开始,一个单一的关闭。

BSD 内核中的 NFS 代码在宏之间使用 goto。它仍然在使用,并且代码实际上可以工作。我知道有几个人曾试图清理这里,但过了一段时间后,他们都放弃了——这里实在太乱了。

你可以在这里看到: Http://www.openbsd.org/cgi-bin/cvsweb/src/sys/nfs/nfsm_subs.h?rev=1.43

有一天我很无聊,在 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)))));

(为简洁起见,没有显示一些函数和类定义)

我曾经看到过一个宏包,它可以给每个 C 关键字起别名,让你可以有效地用克林贡语编程。没错 克林贡语。幸运的是,这个项目几年前就被放弃了。

一位前雇主发现现代 Unix 系统上没有 BASIC-PLUS的实现,所以他们尝试用 C 预处理器宏重新实现它:

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

等等。

太可怕了。

这是从一个流行的开源程序获得的。实际上,它通过隐藏丑陋的遗留内容,使代码的某些部分更具可读性。

#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

参见 这个答案,一个有阅读障碍的同事是如何用一个共同的头文件,像 #define fasle false这样的东西,让自己的生活变得更容易。

一个不懂魔术数字规则的同学说的:
#define TWO_HUNDRED_AND_EIGHTY_THREE_POINT_ONE 283.1

不得不凭记忆做这个,但是大概是这样的: 使用 lib 编写 Symbian 应用程序。隐藏在你 需要要包含的头文件中的是这个小宝石:

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

在我们的代码中,加载具有硬编码文件名的文件失败。当我们把文件位置从 C 盘改为 D 盘的时候,它奇迹般地工作了..。

#define PROCESS_AND_RETURN(X) \
X.process(); \
// Important: Return only after invoking virtual method process() \
return X

由于“重要”注释,宏永远不会返回对象和 CRASH!

我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 中引用的唯一文件。无论何时更改任何内容,都必须重新编译 一切。这是“为了让代码更快”。

温和一点,这是我能想到的通用捕获异常的唯一方法。

我使用它来捕获和阻止异常从我的公共接口函数中传播出去..。

/// 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);}    \
}

我不喜欢它的复杂性,也不喜欢宏,但除此之外,您还能如何“做”一个通用的 catch 处理程序呢?这并不意味着一切都结束了,这只是我的通用 catch 处理程序来隔离遗留的公共函数,并在我知道函数被调用时快速添加 至少在某种程度上的保护,如果抛出一个 C + + 异常,这个函数可能会抛出(欢迎,JNI)。

所以它是让你逃跑和躲藏,还是这是唯一的方法来做这样的事情?

基本上..。

try{
// some block of code capable of throwing
}
CatchAll()

我喜欢这个例子,它使用宏来近似 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; }"