我正在研究Linux container_of
函数,发现typeof括号的使用确实令人困惑。
这是函数#define container_of(ptr, type, member) ({ \
const typeof( ((type*)0)->member) * __mptr =(ptr);\
(type*)( (char*)__mptr - offsetof(type,member) );})
的代码:
const typeof( ((type*)0)->member) * __mptr =(ptr);
在第二行,我们有
max(a,b)
我不明白为什么我们在右侧使用括号。
我在线搜索它,发现有类似用法。例如,从https://gcc.gnu.org/onlinedocs/gcc/Typeof.html,我发现了一个函数#define max(a,b)
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_a > _b ? _a : _b; })
typeof (a) _a = (a);
在这种情况下,我们确实有类似的用法typeof (a) _a = a;
为什么要在右侧使用括号?我们可以删除右侧的括号以使其Sub Test()
吗?
谢谢!
答案 0 :(得分:2)
通过#define
创建的宏执行直接令牌替换。因此,在函数式宏的参数周围使用括号是一种很好的做法,因为它可以防止出现意外问题。
例如:
#define multiply(x, y) x * y
如果您要在此处使用此宏:
int z = multiply(1 + 3, 4 + 5) / 3;
您可能希望z
包含值12,但是您会误认为。
它将上面的内容扩展为:
int z = 1 + 3 * 4 + 5 / 3;
这将导致14。使用括号可以避免此问题。如果将其定义为:
#define multiply(x, y) ((x) * (y))
然后上述示例将扩展为:
int z = ((1 + 3) * (4 + 5)) / 3;
将给出预期的结果。
答案 1 :(得分:0)
使用ptr
宏时,我们不知道参数将用于container_of
。它可能是一个标识符名称,例如MyPointer
。但这可能是一个表达式,例如MyArray + 3
。
宏的常见做法是在替换列表中的参数周围使用括号。例如,如果我们定义square
:
#define square(x) ((x) * (x))
然后将square(3+4)
替换为((3+4) * (3+4))
,根据需要将其设置为49。如果我们改为使用:
#define square(x) (x * x)
然后将square(3+4)
替换为(3+4 * 3+4)
,将其评估为3 + 4*3 + 4
,即3 + 12 + 4
,即19,这是不希望的。
类似地,在您显示的代码中,const typeof( ((type*)0)->member) * __mptr =(ptr);
,ptr
用于初始化名为__mptr
的新定义的对象。为了安全起见,在括号内。它不会改变typeof
的工作方式。
您不应删除这些括号。在这种特定的情况下,ptr
通常不会传递多少内容来破坏没有括号的宏,但是从理论上讲,有一些表达式可能会破坏它。