0

I am studying the Linux container_of function and I find the use of parentheses of typeof is really confusing.

Here is the code of the function container_of:

#define container_of(ptr, type, member) ({ \
    const typeof( ((type*)0)->member) * __mptr =(ptr);\
    (type*)( (char*)__mptr - offsetof(type,member) );})

At the second line, we have

const typeof( ((type*)0)->member) * __mptr =(ptr);

I do not understand why we use parentheses on the right side.

I search it online and find some similar usage. For example, from https://gcc.gnu.org/onlinedocs/gcc/Typeof.html , I found a function max(a,b)

#define max(a,b) 
({ typeof (a) _a = (a); \
  typeof (b) _b = (b); \
  _a > _b ? _a : _b; })

In this case, we do have similar usage typeof (a) _a = (a);

Why should we use parentheses on the right side? Can we remove the parentheses on the right side to make it typeof (a) _a = a;?

Thanks in advance!

Major
  • 159
  • 1
  • 7

2 Answers2

2

Macros created via #define perform direct token substitution. Because of this, using parenthesis around the arguments of a function-like macro is good practice as it prevents unexpected issues from occurring.

For example:

#define multiply(x, y) x * y

If you were to use this macro here:

int z = multiply(1 + 3, 4 + 5) / 3;

You might expect z to contain the value 12, but you would be mistaken.

It would expand the above to:

int z = 1 + 3 * 4 + 5 / 3;

Which would result in 14. Using parenthesis avoids this issue. If it was instead defined as:

#define multiply(x, y) ((x) * (y))

Then the above example would expand to:

int z = ((1 + 3) * (4 + 5)) / 3;

Which would give the expected result.

dbush
  • 205,898
  • 23
  • 218
  • 273
0

We do not know argument will be used for ptr when the container_of macro is used. It might be an identifier name like MyPointer. But it might be an expression, like MyArray + 3.

Common practice in macros is to use parentheses around parameters in the replacement list. For example, if we define square:

#define square(x) ((x) * (x))

Then square(3+4) will be replaced with ((3+4) * (3+4)), which is 49 as desired. If we had instead used:

#define square(x) (x * x)

then square(3+4) would be replaced with (3+4 * 3+4), which would be evaluated as 3 + 4*3 + 4, which is 3 + 12 + 4, which is 19, which is not desired.

Similarly, in the code you show, const typeof( ((type*)0)->member) * __mptr =(ptr);, ptr is being used to initialize a newly defined object named __mptr. It is in parentheses just for safety. It does not change how the typeof operates.

You should not remove these parentheses. In this particular context, there is not much that would normally be passed for ptr that would break the macro without the parentheses, but there are some expressions that are theoretically possible that could break it.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312