3

I find no difference between these two macros except the parentheses surrounding the macro in the first one.

Is it a matter of readability or is it a way to deal with the priority of operators?

#define TAM_ARRAY(a) (sizeof(a)/sizeof(*a))
#define TAM_ARRAY2(a) sizeof(a)/sizeof(*a)
chqrlie
  • 131,814
  • 10
  • 121
  • 189
theriver
  • 325
  • 2
  • 9
  • `is it a way to deal with the priority of operators` Yes. A simple example is macros `#define sum(a,b) a + b`, which in code `sum(1, 2) * 3` will be translated to `1 + (2 * 3)`, not what most people would expect. –  Jul 04 '19 at 22:16

3 Answers3

7

Yes, there is a difference. The parentheses are needed so that the result of the macro is evaluated as a single expression, rather than being mixed with the surrounding context where the macro is used.

The output of this program:

#include <stdio.h>

#define TAM_ARRAY(a) (sizeof(a)/sizeof(*a))
#define TAM_ARRAY2(a) sizeof(a)/sizeof(*a)

int main(void)
{
    int x[4];
    printf("%zu\n", 13 % TAM_ARRAY (x));
    printf("%zu\n", 13 % TAM_ARRAY2(x));
}

is, in a C implementation where int is four bytes:

1
3

because:

  • 13 % TAM_ARRAY (x) is replaced by 13 % (sizeof(x)/sizeof(*x)), which groups to 13 % (sizeof(x) / sizeof(*x)), which evaluates to 13 % (16 / 4), then 13 % 4, then 1.
  • 13 % TAM_ARRAY2(x) is replaced by 13 % sizeof(x)/sizeof(*x), which groups to (13 % sizeof(x)) / sizeof(*x), which evaluates to (13 % 16) / 4, then 13 / 4, then 3.

Along these lines, TAM_ARRAY would be better to include parentheses around the second instance of a as well:

#define TAM_ARRAY(a) (sizeof(a)/sizeof(*(a)))
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Your counter-example is so much more pertinent than mine :) – chqrlie Jul 04 '19 at 22:30
  • 2
    @chqrlie: Thanks. It could actually arise in practice, since there are times when keys are used to insert into arrays in a wrapped manner, so the index is calculated as a remainder of the key modulo array size. I just went to the C standard and hunted for the few operators that would demonstrate a problem. – Eric Postpischil Jul 04 '19 at 22:31
  • Very good indeed. Do you have a non contrived example for `sizeof(*a)`? – chqrlie Jul 04 '19 at 22:34
  • 1
    @chqrlie: I do not see anything. The argument would have to include an operator with lower precedence than unary `*`, but, when the operand to any such operator is an array, it will be converted to a pointer, so `TAM_ARRAY` would not accomplish its purpose anyway. – Eric Postpischil Jul 04 '19 at 22:44
3

Macros are replaced textually in an early phase of code translation. Unless side effects are specifically expected, it is very important to fully parenthesize macro arguments in the macro expansion and the macro expansion itself if it is an expression.

In the case posted, you are unlikely to have a problem because few operators have higher precedence and they would probably not be used around the macro expansion, but here is a pathological example:

  • TAM_ARRAY(a)["abcd"] expands to (sizeof(a)/sizeof(*a))["abcd"] whereas
  • TAM_ARRAY2(a)["abcd"] expands to sizeof(a)/sizeof(*a)["abcd"] which is equivalent to sizeof(a) / (sizeof(*a)["abcd"]).

Note however that an operator with the same precedence placed before the macro expansion such as % would definitely cause problems as explained in Eric Postpischil's answer.

Note also that a should be parenthesized too:

#define TAM_ARRAY(a) (sizeof(a) / sizeof(*(a)))
chqrlie
  • 131,814
  • 10
  • 121
  • 189
2

The way macros work is that the code is "swapped out" when compiling. So something like

#define ADD(i, j) i + j
int k = ADD(1, 2) * 3 

would be seen as: int k = 1 + (2 * 3)

Whereas,

#define ADD(i, j) (i + j)
int k = ADD(1, 2) * 3

would be seen as: int k = (1 + 2) * 3

So, there are two macros likely because of operator priority.

studentbrad
  • 113
  • 7