Thursday, June 23, 2016

Digest for comp.lang.c++@googlegroups.com - 10 updates in 4 topics

ram@zedat.fu-berlin.de (Stefan Ram): Jun 23 10:24PM

Ghost <no@spam.net> writes: Is it possible
>to cast a function pointer into some primitive type and
>back in a safe and portable way?
 
The following program shows how one can convert functions to
ints and vice versa.
 
In the function »main«, the function »integerof« is called
(via »printnumeralof«) to convert each of the functions
»iota« and »zeta« into integers.
 
Then the function »functionof« is called (via
»executefunctionof«) to convert each of the numbers »0« and
»1« into functions.
 
The functions obtained this way than even can be called.
So, the output of the program is:
 
0
1
Lima
Zulu
 
.
 
/*
< filename = [intcall.c]
encoding = [ANSI_X3.4-1968]
notation = [ISO/IEC 9899:1999 (E)]
author = [Stefan Ram] > */
 
#include <stdio.h> /* puts */
#include <string.h> /* strcmp */
 
typedef void( *function_t )( void );
 
#define F(r,n,b) r n b
#define FUNCTIONS \
F( void, iota, ( void ){ puts( "Lima" ); } )\
F( void, zeta, ( void ){ puts( "Zulu" ); } )\
/**/
 
FUNCTIONS
#undef F
 
#define F(r,n,b) n,
void( * const function[] )() ={ FUNCTIONS };
#undef F
 
int const top = sizeof function / sizeof 0[ function ];
 
/** convert an int value into a function */
function_t functionof( int const i ){ return i[ function ]; }
 
/** convert a function into an int value */
int integerof( function_t const f )
{ for( int i = 0; i < top; ++i )
if( f == i[ function ])return i; }
 
void printnumeralof( function_t const f )
{ printf( "%d\n", integerof( f )); }
 
void executefunctionof( int const i )
{ functionof( i )(); }
 
int main( void )
{ printnumeralof( iota );
printnumeralof( zeta );
executefunctionof( 0 );
executefunctionof( 1 ); }
Ghost <no@spam.net>: Jun 23 02:05PM -0300

HI there,
 
I find myself in a situation where I can only pass around
structs with no pointer members. However, I would like to
include information about function pointers. Is it possible
to cast a function pointer into some primitive type and
back in a safe and portable way? If I use reinterpret_cast,
is the success of the operation only a matter of the new
type being large enough?
 
If it is of any help, I'm trying to use the standardized
Fortran mechanism to mix Fortran and C, but I can only
have Fortran /derived types/ be mapped into C structs
if no pointer members are involved. Also, Fortran doesn't
define /interoperability/ between Fortran and C++, so I
also mix C++ and C using extern "C". Another limitation is
that Fortran doesn't have unsigned types.
 
Any help appreciated.
Thanks.
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 23 01:38PM -0400

On 6/23/2016 1:05 PM, Ghost wrote:
> is the success of the operation only a matter of the new
> type being large enough?
 
> [..]
 
Yes, all correct, if your implementation provides an integral type large
enough to accommodate a pointer (to function, to object), you can use
'reinterpret_cast' to do the casting forth and back between a pointer
and that integral type. There is no standard type, it's all
implementation-specific ([expr.reinterpret.cast]/4 and /5).
 
V
--
I do not respond to top-posted replies, please don't ask
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jun 23 07:53PM +0100

> include information about function pointers. Is it possible
> to cast a function pointer into some primitive type and
> back in a safe and portable way?
 
I don't think you can do it with a cast in a 100% portable way. You can
include cstdint and test for UINTPTR_MAX which will tell you if there is
a type uintptr_t type that can hold a pointer value (or, alternatively,
INTPTR_MAX for the signed version) but even that is only guaranteed to
work for object pointers.
 
The only portable method would be to copy the representation:
 
typedef void (*function_ptr)();
unsigned char fptr_rep[sizeof (function_ptr)];
...
function_ptr fp = ...;
memcpy(fptr_rep, &fp, sizeof fp);
 
but that, of course, is clumsy.
 
<snip>
--
Ben.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 23 09:13PM +0200

On 23.06.2016 20:53, Ben Bacarisse wrote:
> a type uintptr_t type that can hold a pointer value (or, alternatively,
> INTPTR_MAX for the signed version) but even that is only guaranteed to
> work for object pointers.
 
Since C++11 an implementation can support casting function pointer to
void* and back. Essentially because the Posix API requires that. And
then uintptr_t is necessarily large enough.
 
C++11 §5.2.10/8:
«Converting a function pointer to an object pointer type or vice versa
is conditionally-supported. The meaning of such a conversion is
implementation-defined, except that if an implementation supports
conversions in both directions, converting a prvalue of one type to the
other type and back, possibly with different cv-qualification, shall
yield the original pointer value.»
 
 
 
> function_ptr fp = ...;
> memcpy(fptr_rep, &fp, sizeof fp);
 
> but that, of course, is clumsy.
 
Yep.
 
But I'd go for the portable-enough uintptr_t. ;-)
 
 
Cheers!,
 
- Alf
legalize+jeeves@mail.xmission.com (Richard): Jun 23 07:32PM

[Please do not mail me a copy of your followup]
 
Ghost <no@spam.net> spake the secret code
 
>[...] Is it possible
>to cast a function pointer into some primitive type and
>back in a safe and portable way?
 
Not really
 
<http://stackoverflow.com/questions/12358843/why-are-function-pointers-and-data-pointers-incompatible-in-c-c>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jun 23 09:13PM +0100


> Since C++11 an implementation can support casting function pointer to
> void* and back. Essentially because the Posix API requires that. And
> then uintptr_t is necessarily large enough.
 
Yes, I wasn't very clear at all. I should have pointed out that
converting to uintptr_t only works for void * (I think C++ defers to C
on this matter) so you can't ever convert a function pointer directly.
(in the standard sense that is -- it is, of course, very likely to work
in practice). Thus two things are needed: the uintptr_t type and the
(two-way) conversion between function pointers and object pointers.
 
> C++11 §5.2.10/8:
 
Thanks for the quote. I didn't know this happened so late!
 
<snip>
>> The only portable method would be to copy the representation:
<snip>
> But I'd go for the portable-enough uintptr_t. ;-)
 
Sure, me too, but the OP's request was so odd (why no function pointers
in the structures?) that they may be looking at some very odd hardware
that really can't do it any other way.
 
--
Ben.
scott@slp53.sl.home (Scott Lurndal): Jun 23 08:19PM


>Sure, me too, but the OP's request was so odd (why no function pointers
>in the structures?) that they may be looking at some very odd hardware
>that really can't do it any other way.
 
He's sharing the structure between fortran and C, and fortran
creates the C-structure definition used based on the COMMON
data being shared.
kfrank29.c@gmail.com: Jun 22 06:31PM -0700

Hi Mehrdad!
 
On Wednesday, June 22, 2016 at 11:07:15 AM UTC-4, mehrdad ghassempoory wrote:
 
> however, if I use clang++ version 3.5, I get what I expected:
 
> 0 2
 
> Is this a bug in gnu c++
 
This is not a bug in g++. Both g++ and clang++ are right,
because (see below) your program has unspecified behavior,
which means that the standard gives the compiler a choice,
and g++ and clang++ are (apparently) making different choices.
 
> or maybe I am confused about the way <<
> operator works?
 
Because the library uses "operator overloading" to let
"<<" work with streams, "<<", in your case, is just a
function that takes two arguments.
 
The order of evaluation of arguments to functions is
unspecified by the standard, so either the first or the
second argument may be evaluated first. (This is not
changed by the fact that your function call is written
as an infix operator.)
 
> int x;
 
> x=0;
> cout << func(x) << " " << x << endl;
 
To see what is happening, let's rewrite this with explicit
function-call notation:
 
operator<< (
operator<< ( // this is the relevant function call
operator<< (
operator<< ( cout, func(x) ),
" ",
),
x
),
endl
);
 
The second "operator<<" (noted by the comment) is called
with two arguments. The first is the result of evaluating
the third "operator<<", and the second is x, itself.
 
If you evaluate the first argument first (as, apparently,
does clang++) you drill down and call func(x) which sets
x to 2 (and returns zero). You then evaluate x, which is
now 2. So you print out "0 2".
 
If you evaluate the second argument first (as, apparently,
does g++), you evaluate x, which is 0, and then call func(x),
which sets x to 2 -- but this does not change the value of
0 from the earlier evaluation of x -- and returns 0. So you
print of "0 0".
 
> ...
 
To recap: Both results, "0 2" and "0 0" are perfectly legal,
because they depend upon in which order the two arguments
of operator<< are evaluated, and this is explicitly stated
to be unspecified in the standard, with the choice left up
to the compiler.
 
 
Good luck.
 
 
K. Frank
Kalle Olavi Niemitalo <kon@iki.fi>: Jun 23 03:09AM +0300


> The question really should be "why does g++ accept this non-standard
> escape sequence?". Which, of course, only the authors, documentation
> and/or source code comments of g++ can tell you.
 
The C source code of GNU Emacs often uses \( to escape the
opening parenthesis when it occurs at the beginning of a line in
a multiline string literal. AFAIK, this helps Emacs understand
that the parenthesis does not mark the start of a function,
when the source code of Emacs is being edited with Emacs itself.
Because GCC and Emacs are flagship GNU packages, it seems
reasonable for GCC not to warn about Emacs conventions by
default.
 
https://www.gnu.org/prep/standards/html_node/Formatting.html
also advises against starting a line with an opening parenthesis.
It does not mention the backslashes though.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: