0

Why is this code compiling correctly for the arithmetic on a function pointer?

void my_func(void);

int main(void)
{
    void (*p)(void) = &my_func;

    // Compile
    (void) (*p);
    (void) *(p + 0);

    // Does not compile
    (void) p[0];

    return 0;
}

I have always thought that p[0] == *(p + 0) for complete types. Apparently, p[0] != *(p + 0) for function pointers.

Note: the C standard does not explicitly forbid function pointer arithmetic. It does not forbid it at all. It says it is undefined. That is a different thing. Many language extensions that are conforming in the terms of the standard have behavior that is undefined by the standard.


Also, if you use a pointer to an incomplete type, then we have:

int main(void)
{
    int (*p)[];

    // Compile
    (void) (*p);

    // Does not compile
    (void) *(p + 0);
    (void) p[0];

    return 0;
}

Then effectively p[0] == *(p + 0) because both triggers the same error for arithmetic on an pointer to an incomplete type. Although here, the C standard does explicitly forbid arithmetic on an pointer to an incomplete type.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
explogx
  • 1,159
  • 13
  • 28

1 Answers1

1

Array subscripting a[b] needs one of a or b to be a pointer to a complete object type. A function type is not a complete object type.

6.5.2.1 Array subscripting

Constraints

1 One of the expressions shall have type "pointer to complete object type", the other expression shall have integer type, and the result has type "type".

Note that p + 0 should also be an error for the same reason, and I believe the compiler is failing to produce a required diagnostic message. I asked this about why it's not produced: Should clang and gcc produce a diagnostic message when a program does pointer arithmetic on a function pointer?

6.5.6 Additive operators

Constraints

For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)

Paul Hankin
  • 54,811
  • 11
  • 92
  • 118
  • It's unclear to me why `p+0` compiles, since the conditions for `+` are that both arguments are arithmetic types, or one is a pointer to a complete object type, so I think there's something missing in this answer. – Paul Hankin May 21 '20 at 10:28
  • Well, so `*(p + 0)` compiles just because this is an uhandled error/warning by the compiler, and still undefined behavior per the C standard? Because yes, the C standard explicitly forbids function pointers arithmetic. – explogx May 21 '20 at 10:34
  • @eigenslacker: The C standard does not explicitly forbid function pointer arithmetic. It does not forbid it at all. It says it is undefined. That is a different thing. Many language extensions that are *conforming* in the terms of the standard have behavior that is undefined by the standard. If “undefined” meant “forbidden,” those would not be possible. It does not mean “forbidden.” – Eric Postpischil May 21 '20 at 11:18
  • @EricPostpischil I believe the C standard does forbid function pointer arithmetic, and the compiler is required to produce an error message. I asked https://stackoverflow.com/questions/61949561/should-clang-and-gcc-produce-a-diagnostic-message-when-a-program-does-pointer-ar with links to the standard. – Paul Hankin May 22 '20 at 07:11
  • @eigenslacker I think you're right it's forbidden by the standard, but I think it's also required that the compiler produces a diagnostic message because it's a constraint violation. I asked this question, with links to the standard: https://stackoverflow.com/questions/61949561/should-clang-and-gcc-produce-a-diagnostic-message-when-a-program-does-pointer-ar – Paul Hankin May 22 '20 at 07:12
  • @PaulHankin: The question you posted does not ask whether function pointer arithmetic is forbidden. It asks whether a diagnostic message is required. Those are different things. – Eric Postpischil May 22 '20 at 10:40