4

In the C programming language, we are given the guarantee that a function pointer may legally be converted to a function pointer of a different type and back without loss of data:

Section 6.3.2.3, paragraph 8:

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer.

This rule indirectly guarantees that the sizeof one function pointer must be the same as the sizeof any other function pointer, since no loss of data may occur.

However, I am having difficulty finding any similar passages in the C++ standard (currently reading the C++17 standard, if that matters). There are actually few mentions I can find of any conversions to do with function pointers explicitly, but neither conv.ptr nor basic.compound really provide any similar guarantees.

My question is this: Does C++ provide the same guarantee that C does that any (non-member) function pointer may hold the value of any other (non-member) function pointer?


I was hoping to find this already asked, but the closest I could find was this similar question for C (which is not guaranteed to be the same answer as C++), and a bunch of unrelated questions about sizes of member pointers.

To emphasize: This is not asking whether it may work because a compiler supports both C and C++; this is asking whether the C++ abstract machine officially supports this same conversion.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Human-Compiler
  • 11,022
  • 1
  • 32
  • 59
  • 2
    [conc.ptr] is more about standard conversions that can be performed implicitly. Function pointer conversion requires a cast. I'd look in the section describing the appropriate one. – StoryTeller - Unslander Monica Mar 06 '21 at 00:45
  • I haven't checked the standards lately, but I remember that in the past you could not assume that a function pointer was the same size as a data pointer. The rules are more defined for POSIX or Win32 though. But I know this isn't what you asked. – Zan Lynx Mar 06 '21 at 00:50
  • 1
    I disagree with the interpretation that the rule you quote guarantees that `sizeof` gives the same result on two different function pointers. The rule *permits* that, but that's not the same as *requiring* it. There are plenty of ways to guarantee that a value survives a round-trip conversion (i.e. "type A to type B back to type A" and "type B to type A to type B" both yield the original value) without requiring that the two types have the same size. If one size is larger and the extra bits/bytes are unused, the conversion to/from the larger type only needs to copy the used bits. – Peter Mar 06 '21 at 01:14

1 Answers1

8

Yes, quoting from expr.reinterpret.cast/6:

A function pointer can be explicitly converted to a function pointer of a different type.

[Note 5: The effect of calling a function through a pointer to a function type ([dcl.fct]) that is not the same as the type used in the definition of the function is undefined ([expr.call]). — end note]

Except that converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are function types) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.

[ EDIT ]   The "yes" part of the answer refers to OP's question as worded in the body of the post: "does C++ provide the same guarantee that C does that any (non-member) function pointer may hold the value of any other (non-member) function pointer?".

As pointed out in @NateEldredge's comments, this does not automatically imply that "all non-member function pointers [are] the same size in C++" (as the title of the question reads), though it would strongly suggest that they do.

dxiv
  • 16,984
  • 2
  • 27
  • 49
  • 5
    This doesn't actually guarantee that the `sizeof`s are equal, though, does it? Maybe on the DeathStation 9000 a `void (*)()` is 4 bytes, and an `int (*)()` is 8 bytes, but the extra 4 bytes are always `0xdeadbeef` and so they can be converted back and forth without loss. – Nate Eldredge Mar 06 '21 at 00:57
  • 1
    @NateEldredge That's technically correct, and the OP themselves recognized that ("*indirectly* guarantees that..."). The above does however answer the question written in the body of the post, whether "*any (non-member) function pointer may hold the value of any other (non-member) function pointer*". – dxiv Mar 06 '21 at 01:00
  • 1
    So "guarantees" is maybe slightly too strong. Perhaps "strongly suggests". – Nate Eldredge Mar 06 '21 at 01:02
  • @NateEldredge Right again, hope the edit clarifies this better. – dxiv Mar 06 '21 at 01:09
  • @NateEldredge - The terminology "strongly suggests" has no place in interpreting a standard. It is only in the heads of language lawyers trying to find an excuse to do something. Something is required, permitted, or not permitted. – Peter Mar 06 '21 at 01:39
  • @Peter: Indeed, and so in that sense, it seems that function pointer sizes are *permitted* to be different. Outside the world of standard interpretation, however, one would expect that *most* real-life implementations will *probably* make them the same size - just because if they have to be freely convertible, there's no apparent reason to make them different sizes, other than sheer spite. – Nate Eldredge Mar 06 '21 at 01:46
  • I think I probably worded the original question a little too strictly; I was primarily interested in whether the round-trip conversion itself would be valid in C++ just as it is in C -- which the cited passage answers. Thank you! – Human-Compiler Mar 06 '21 at 01:49
  • 1
    @NateEldredge I do remember some older C implementations that supported pointer of different types with different sizes, based on a segmented memory architecture (physically distinct banks of memory (or storage) where some types of objects would be stored but not others). Part of the pointer representation identified the memory area where the object was typically stored - that information was of varying size, and conversion of pointers between different types simply didn't copy that information - which had an effect that the pointer value would survive a round-trip conversion. – Peter Mar 06 '21 at 02:12