Ignoring implementation details and strictly following the C99
standard in terms of semantics, is there anything fundamentally flawed
with describing the use of a (non-inline) function as an address[1]? ...
[1] To keep things in context, this is in reference to describing
functions to a beginner.
I think the biggest problem with that is that it will just confuse
the beginner.
A (non-inline) function is, after all, compiled to a bunch of
executable instructions, on most of today's machines with most
of today's compilers. Those instructions eventually wind up
with "code-space addresses", but you get more than just *an*
address, you get a whole range of addresses. It makes more sense,
I think, to say that the function itself occupies that entire
range. Of cours, after declaring "void f(void);", the line:
sizeof f
produces a compile-time error, but this is due to the language
decreeing that no C compiler has to be able to divine the eventual
final size of a function at the point that the "sizeof" occurs.
(This is natural enough, since the function may not even have been
compiled yet. Of course, there are ways to deal with this, by
making "sizeof f" be a link-time constant instead of a compile-time
constant, but the language does not require that.)
The language specifies that, once you have declared that a some
identifier refers to a function, simply naming the function (without
actually calling it) normally produces a pointer to that function.
This pointer is a form of "address value", and the address you get
on real machines is, in general, the address of the first instruction
-- or the first byte of the first instrution -- of the function.
(Even this is not guaranteed. On the VAX, for instance, the first
*executable* byte of the function is two bytes *after* the start
of the function. Functions begin with a two-byte "register save
mask" word. The function pointer points to this word. On other
machines, a function pointer may point to a "function descriptor",
rather than to the actual code for the function. Descriptors may
be collected together at compile and/or link time, or may simply
precede each function.)
Ultimately, the C beginner -- in order to become a non-beginner --
has to grasp the idea that the C language "likes to" take something
that covers a large range of machine addresses, like an array or
a function, and "squish it down" to a pointer to the *start* of
that large range. This is the origin of the idea of the "decay"
of an array or function name, which both *usually* turn into a
pointer value, pointing to the "start" of the larger entity. But
this "decay" is suppressed in particular cases, such as using
the "sizeof" operator.