如何处理宏 [英] how to handle macros

查看:105
本文介绍了如何处理宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以解释这个宏中发生的事情,因为我是c和宏的新手



#define FIELD_OFFSET(type,field)((LONG)(LONG_PTR )&(((type *)0) - > field))

Can anyone explain what is happening in this macro as I am new to c and macros

#define FIELD_OFFSET(type, field) ((LONG)(LONG_PTR)&(((type *)0)->field))

推荐答案

我会解释一些更常见的要点,以考虑处理宏。

C中的宏只是文本替换,最简单的形式是宏是要被另一个文本替换的文本:

I would explain some more general points to take into account dealing with macros.
Macros in C are just text replacements, in the simplest form a macro is a text to be replaced by another text:
#define OldText NewText



宏的一个更高级的功能是传递参数的可能性。在这种情况下,要搜索和替换的文本是宏名称,而参数中的文本将替换在宏体中出现参数名称的位置:


A more advanced feature of macros is the possibility of passing parameters. In this case the text to search and replace is macro name, while the text in the parameters is replaced in the positions where the parameters names appears in the macro body:

#define macro1(par1, par2) par1 = par2;



在最后一个例子中,如果我们写:


In the last example if we write:

macro1(a, 4)



文件预处理后,我们将得到:


After file preprocessing we will get:

a = 4;



参数的数量甚至可以是变量,这使用省略号和特殊符号__VA_ARGS__声明,转换为变量参数序列:


The number of parameters can even be variable, this declared using the elipsis and the special symbol __VA_ARGS__ that translates to the sequence of variable parameters:

#define PRINTMACRO(format, ...)  printf(format, __VA_ARGS__);



在这种情况下,行:


In this case the line:

PRINTMACRO("string %s and int %d\n", string, a);



后处理器将导致:


Afte preprocessor will lead to:

printf("string %s and int %d\n", string, a);





现在澄清之后,回到你的问题,让你困惑的宏并不复杂,因为'宏',但它是如何使你困惑的写作。

如果是这种情况,让我们仔细看看。首先摆脱teh macro capsule并分析内容:



Now after this clarification, going back to your question the macro that made you perplex is not complicate as a 'macro', but is how it is write that made you perplex.
If this is the case let have a closer look to it. First of all get rid of teh macro capsule and let analyze the content:

((LONG)(LONG_PTR)&(((type *)0)->field))



来自内部的考试:< b>((type *)0)这里我们将值0(零)转换为类型变量的地址(指向变量的指针)。到目前为止,它可以是任何类型的变量,但是会理解并非如此。

事实上的扩展:(((type *)0) - > field)我们知道我们从指向类型类型的结构的指针获取成员字段,该地址为0.

进一步:&(((type *) 0) - >字段)我们在地址0处获取类型类型结构的成员字段的地址。

现在只需考虑一下:如果在地址0处考虑结构,每个字段的地址与从结构的开始的字节偏移(以字节为单位)一致。但偏移是一个数字,在这里我们得到一个地址。这可以在编译期间对类型兼容性创建警告。我们需要将结果转换为数字。

这就是我们现在所做的,我们将地址转换为 LONG ,但在我们将结果转换为 LONG_PTR 。

这是一个MS宏,它可以用于32位和64位程序集。这就是为什么我们首先将它投射到LONG_PTR:(LONG_PTR)&(((type *)0) - > field) LONG_PTR 是一种保证接受任何处理器位数的long和指针的类型,因此避免编译器警告。

然后最后一步是将值转换为偏移量必须是:一个数字。


Exam from the inside: ((type *)0) here we cast the value 0 (zero) as the address of a type variable (a pointer to variable). Up to now it can be any kind of variable, but will understand that is not so.
Infact extending: (((type *)0)->field) we understand that we are getting the member 'field' from a pointer to a struct of type 'type', which address is 0.
Further on: &(((type *)0)->field) we are getting the address of the member 'field' of a structure of type 'type' at address 0.
Just a consideration is required now: if a structure is considered at address 0, the address of each field is coincident with the field offset, in bytes, from the start of the structure. But an offset is a number, and here we got an address. This can create warnings on types compatibility during compilation. We need to cast the result to a number.
This is what we do now, we cast our address to a LONG, but before we cast the result to a LONG_PTR.
This is an MS macro, and it is crafted to work for 32 and 64 bits assemblies. That's why we cast it first to LONG_PTR: (LONG_PTR)&(((type *)0)->field). LONG_PTR is a type that guarantee to accept longs and pointers for any processor bitness so avoid compiler warnings.
Then the last step is to cast value to what an offset must be: a number.

((LONG)(LONG_PTR)&(((type *)0)->field))



士气并不担心宏,你必须遵循C规则来理解代码;)。

这是一个好习惯,总是将每个参数括起来,然后将整个宏括在括号中,以避免表达式产生任何副作用(不要这样做,很快或以后你会发现为什么你必须:D )。



最后,为什么所有的大括号?

考虑:


The morale is don't worry about the macro it is C rules you have to follow to un derstand the code ;).
It is a good habit to always enclose each parameter and then the whole macro in braces to avoid any side effect from the expression (don't do this and soon or later you'll find why you have to :D).

Last, why all that braces?
Consider:

struct _tagstr
{
    int a;
    float b;
};

void *pStr;

...

//We are pretending that at the location pointed by pStr there is a a structure
//like _tagstr to which we assign the float value 0.1
// (Yes an obscure feature of C :-) )
*((float *)((char *)pStr + FIELD_OFFSET(struct _tagstr, b))) = 0.1;



最好是严格界定宏的参数。

我希望这会给这个问题带来更多的亮点。 br />


PS将我的上一个示例视为练习;)


It's alway better to strictly delimit parameters of macros.
I hope this will give some more lights on the issue.

P.S. consider my last example as an exercise ;)


它给出结构<$ c中项字段的偏移量(以字节为单位) $ C>型。所以,如果你有以下结论:

It gives the offset, in bytes, of item field in the structure type. So if you have s tructure as follows:
struct foo
{
    int fooInt;     // 4 bytes wide, starting at offset 0
    char fooChar;   // 1 byte wide, starting at offset 4
};
FIELD_OFFSET(foo, fooChar) = 4;



极少数情况下你会需要使用它,尽管我已经完成了自己,在昏暗和遥远的过去。


There are very few cases where you would need to use it, allthough I have done myself, in the dim and distant past.


这篇关于如何处理宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆