I'm sure I'll get 20 people saying "why would you want to do that anyways"... but, I'm going to ask my question none-the-less because it's somewhat academic in nature.
我相信我会得到20个人说“你为什么要这样做呢”......但是,我会问我的问题,因为它有点学术性质。
I'd like to use C macros to redefine [ClassName new]
into something like: new(ClassName)
, and I'm wondering how to do this. I'm not super comfortable with C macros to begin with (I know - embarrassing - I should be) - and I'm definitely not comfortable mixing them in with my Objective-C code. So, on with the question...
我想使用C宏将[ClassName new]重新定义为:new(ClassName),我想知道如何做到这一点。我开始时对C宏不太满意(我知道 - 令人尴尬 - 我应该这样) - 我绝对不喜欢将它们与我的Objective-C代码混合使用。那么,关于这个问题......
First, being it's a preprocessor thing, can I do a simple substitution like such:
首先,它是一个预处理器,我可以做一个简单的替换:
#define new(x) [x new]
or, for whatever reason, do I need to drop down to the objective-c runtime, and do something more akin to:
或者,无论出于何种原因,我是否需要下载到objective-c运行时,并执行更类似于以下的操作:
#define new(x) objc_msgSend(class_createInstance(x, 0), sel_registerName("init"))
What are the downfalls of doing something like this?
做这样的事情会有什么不足之处?
Is this kind of thing used often by others, or, would someone look at it and say "what the heck are you doing there"? (and should I care)
这种事情是否经常被其他人使用,或者,有人会看着它说“你到底在做什么”? (我应该关心)
Thanks
谢谢
EDIT:
编辑:
It occurred to me after posting this, that I have, in fact, see this kind of thing before - in the Three20 lib, where they do things like this:
事实上,在我发布之后,事实上我已经看到了这种事情 - 在Three20 lib中,他们做了这样的事情:
#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
#define TT_INVALIDATE_TIMER(__TIMER) { [__TIMER invalidate]; __TIMER = nil; }
// Release a CoreFoundation object safely.
#define TT_RELEASE_CF_SAFELY(__REF) { if (nil != (__REF)) { CFRelease(__REF); __REF = nil; } }
So probably my question becomes simply; What are the downfalls of doing this, and is it a relatively accepted practice, or something that's going to get me into more trouble than it's worth?
所以我的问题可能变得简单;这样做有什么不足之处,这是一种相对公认的做法,还是会让我陷入更多麻烦的事情呢?
3 个解决方案
#1
3
Macros are processed first, and they are operating on the plain text source code. So yes, you can have your new
macro generate Objective-C syntax or plain C syntax or even invalid syntax if you like.
首先处理宏,并且它们在纯文本源代码上运行。所以是的,如果你愿意,可以让你的新宏生成Objective-C语法或普通的C语法甚至无效的语法。
The downfalls of using a macro in general is that, because it is parsed and processed in a separate step, it's possible to write macros that don't behave how you expect even when everything looks fine.
一般使用宏的缺点是,因为它是在单独的步骤中解析和处理的,所以即使一切看起来都很好,也可以编写不符合预期的宏。
For example, this macro:
例如,这个宏:
#define MAX(x,y) x > y ? x : y
Looks OK, but say you used it like this:
看起来不错,但是你说你用它是这样的:
z = MAX(a,MAX(b,c));
It would be expanded by the preprocessor into something like this:
它将由预处理器扩展为如下所示:
z = a > b > c ? b : c ? a : b > c ? b : c;
Which won't actually give you the max of the three arguments. To solve this you need to liberally sprinkle parenthesis in your macro definition, even where you don't think it is needed:
哪个实际上不会给你三个参数的最大值。要解决这个问题,您需要在宏定义中*地使用括号,即使您认为不需要它也是如此:
#define MAX(x,y) ((x) > (y) ? (x) : (y));
That fixes it, except I added a semicolon to the end, which is an understandable habit from writing a lot of C code, except now our macro expands to:
这修复了它,除了我添加了一个分号到最后,这是一个可以理解的习惯,写了很多C代码,除了现在我们的宏扩展到:
z = ((a) > (((b) > (c) ? (b) : (c));) ? (a) : (((b) > (c) ? (b) : (c));));;
Syntax errors!
语法错误!
If you look at how MAX
is actually defined in Objective-C, it's pretty mess, but that's what you have to do to write macros safely. And you also need to consider that:
如果你看一下在Objective-C中实际定义的MAX是多么糟糕,但这就是你必须要做的安全编写宏。而你还需要考虑:
z = MAX(expensiveComputation(), reallyExpensiveComputation())
Will, unlike a function, actually execute one of those functions twice, unless you use a trick in your macro to basically emulate parameter passing.
与函数不同,它实际上会执行两次这样的函数之一,除非你在宏中使用一个技巧来基本上模拟参数传递。
So, to answer your question, yes it is totally possible, but writing safe macros is really hard. And you're doing this so you can pretend your Objective-C code is actually code in another language... Why would you want to do that, anyways?
所以,回答你的问题,是的,它完全有可能,但编写安全的宏非常困难。你正在这样做,所以你可以假装你的Objective-C代码实际上是另一种语言的代码......为什么你想这样做呢?
#2
3
C macros are guaranteed
C宏是有保证的
- not to be recursive
- 不要递归
- not to expand functionlike macros that are not followed by
()
- 不扩展未跟随的函数式宏()
so your first variant would be ok for the C preprocessor. The only identifiers that are reserved (so you couldn't use for macro names) are keywords and identifiers starting with underscore. new
is neither keyword (for C) nor starting with an underscore, so this is fine for the C preprocessor.
所以你的第一个变种对于C预处理器来说是可以的。保留的唯一标识符(因此您不能用于宏名称)是以下划线开头的关键字和标识符。 new既不是关键字(对于C)也不是以下划线开头,因此对于C预处理器来说这很好。
I don't know if the objective-C imposes other restrictions, you'd have to look that up.
我不知道目标-C是否施加了其他限制,你必须要查看它。
And yes I am definitively the guy who asks "why would you want to do that anyways?". Don't do that, don't even think of doing that, if on the other hand you feel the need to ask your question.
是的,我绝对是那个问“为什么你还想这样做呢?”的人。不要这样做,甚至不要这样做,如果另一方面你觉得有必要问你的问题。
#3
1
Assuming you are using a recent GCC (that is a 4.6 version), you might consider making a GCC plugin, or preferably a GCC MELT extension, for such a task. MELT is a high-level domain specific language to easily extend GCC.
假设您使用的是最近的GCC(即4.6版本),您可以考虑为此类任务制作GCC插件,或者最好是GCC MELT扩展。 MELT是一种高级域特定语言,可以轻松扩展GCC。
For instance, your new
macro would be
例如,你的新宏将是
#define new(X) _mybuiltin_new_(X)
and then your MELT extension would add a new GCC builtin _mybuiltin_new_
which would be transformed into some simpler Gimple (the internal representation used by GCC). However, these kind of things take some time (a week at least, not hours) to be developed.
然后你的MELT扩展将添加一个新的GCC内置_mybuiltin_new_,它将转换成一些更简单的Gimple(GCC使用的内部表示)。然而,这些事情需要一些时间(至少一周,而不是几小时)来开发。
#1
3
Macros are processed first, and they are operating on the plain text source code. So yes, you can have your new
macro generate Objective-C syntax or plain C syntax or even invalid syntax if you like.
首先处理宏,并且它们在纯文本源代码上运行。所以是的,如果你愿意,可以让你的新宏生成Objective-C语法或普通的C语法甚至无效的语法。
The downfalls of using a macro in general is that, because it is parsed and processed in a separate step, it's possible to write macros that don't behave how you expect even when everything looks fine.
一般使用宏的缺点是,因为它是在单独的步骤中解析和处理的,所以即使一切看起来都很好,也可以编写不符合预期的宏。
For example, this macro:
例如,这个宏:
#define MAX(x,y) x > y ? x : y
Looks OK, but say you used it like this:
看起来不错,但是你说你用它是这样的:
z = MAX(a,MAX(b,c));
It would be expanded by the preprocessor into something like this:
它将由预处理器扩展为如下所示:
z = a > b > c ? b : c ? a : b > c ? b : c;
Which won't actually give you the max of the three arguments. To solve this you need to liberally sprinkle parenthesis in your macro definition, even where you don't think it is needed:
哪个实际上不会给你三个参数的最大值。要解决这个问题,您需要在宏定义中*地使用括号,即使您认为不需要它也是如此:
#define MAX(x,y) ((x) > (y) ? (x) : (y));
That fixes it, except I added a semicolon to the end, which is an understandable habit from writing a lot of C code, except now our macro expands to:
这修复了它,除了我添加了一个分号到最后,这是一个可以理解的习惯,写了很多C代码,除了现在我们的宏扩展到:
z = ((a) > (((b) > (c) ? (b) : (c));) ? (a) : (((b) > (c) ? (b) : (c));));;
Syntax errors!
语法错误!
If you look at how MAX
is actually defined in Objective-C, it's pretty mess, but that's what you have to do to write macros safely. And you also need to consider that:
如果你看一下在Objective-C中实际定义的MAX是多么糟糕,但这就是你必须要做的安全编写宏。而你还需要考虑:
z = MAX(expensiveComputation(), reallyExpensiveComputation())
Will, unlike a function, actually execute one of those functions twice, unless you use a trick in your macro to basically emulate parameter passing.
与函数不同,它实际上会执行两次这样的函数之一,除非你在宏中使用一个技巧来基本上模拟参数传递。
So, to answer your question, yes it is totally possible, but writing safe macros is really hard. And you're doing this so you can pretend your Objective-C code is actually code in another language... Why would you want to do that, anyways?
所以,回答你的问题,是的,它完全有可能,但编写安全的宏非常困难。你正在这样做,所以你可以假装你的Objective-C代码实际上是另一种语言的代码......为什么你想这样做呢?
#2
3
C macros are guaranteed
C宏是有保证的
- not to be recursive
- 不要递归
- not to expand functionlike macros that are not followed by
()
- 不扩展未跟随的函数式宏()
so your first variant would be ok for the C preprocessor. The only identifiers that are reserved (so you couldn't use for macro names) are keywords and identifiers starting with underscore. new
is neither keyword (for C) nor starting with an underscore, so this is fine for the C preprocessor.
所以你的第一个变种对于C预处理器来说是可以的。保留的唯一标识符(因此您不能用于宏名称)是以下划线开头的关键字和标识符。 new既不是关键字(对于C)也不是以下划线开头,因此对于C预处理器来说这很好。
I don't know if the objective-C imposes other restrictions, you'd have to look that up.
我不知道目标-C是否施加了其他限制,你必须要查看它。
And yes I am definitively the guy who asks "why would you want to do that anyways?". Don't do that, don't even think of doing that, if on the other hand you feel the need to ask your question.
是的,我绝对是那个问“为什么你还想这样做呢?”的人。不要这样做,甚至不要这样做,如果另一方面你觉得有必要问你的问题。
#3
1
Assuming you are using a recent GCC (that is a 4.6 version), you might consider making a GCC plugin, or preferably a GCC MELT extension, for such a task. MELT is a high-level domain specific language to easily extend GCC.
假设您使用的是最近的GCC(即4.6版本),您可以考虑为此类任务制作GCC插件,或者最好是GCC MELT扩展。 MELT是一种高级域特定语言,可以轻松扩展GCC。
For instance, your new
macro would be
例如,你的新宏将是
#define new(X) _mybuiltin_new_(X)
and then your MELT extension would add a new GCC builtin _mybuiltin_new_
which would be transformed into some simpler Gimple (the internal representation used by GCC). However, these kind of things take some time (a week at least, not hours) to be developed.
然后你的MELT扩展将添加一个新的GCC内置_mybuiltin_new_,它将转换成一些更简单的Gimple(GCC使用的内部表示)。然而,这些事情需要一些时间(至少一周,而不是几小时)来开发。