Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #384057 > unrolled thread
| Started by | gazelle@shell.xmission.com (Kenny McCormack) |
|---|---|
| First post | 2024-03-28 15:09 +0000 |
| Last post | 2024-03-29 15:52 -0700 |
| Articles | 14 on this page of 34 — 11 participants |
Back to article view | Back to comp.lang.c
Casting the return value of ... gazelle@shell.xmission.com (Kenny McCormack) - 2024-03-28 15:09 +0000
Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 18:16 +0000
Re: Casting the return value of ... scott@slp53.sl.home (Scott Lurndal) - 2024-03-28 18:53 +0000
Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-03-30 10:33 -0700
Re: Casting the return value of ... scott@slp53.sl.home (Scott Lurndal) - 2024-03-30 19:29 +0000
Re: Casting the return value of ... Lawrence D'Oliveiro <ldo@nz.invalid> - 2024-03-30 23:05 +0000
Re: Casting the return value of ... scott@slp53.sl.home (Scott Lurndal) - 2024-03-30 23:25 +0000
Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-31 15:44 +0200
Re: Casting the return value of ... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2024-03-31 13:15 -0700
Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-04-08 23:01 -0700
Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-04-09 10:03 +0200
Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 12:38 -0700
Re: Casting the return value of ... bart <bc@freeuk.com> - 2024-03-28 20:30 +0000
Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 14:07 -0700
Re: Casting the return value of ... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2024-03-28 14:15 -0700
Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 21:44 +0000
Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 22:01 +0000
Re: Casting the return value of ... Kaz Kylheku <433-929-6894@kylheku.com> - 2024-03-28 22:33 +0000
Re: Casting the return value of ... Michael S <already5chosen@yahoo.com> - 2024-03-29 15:53 +0200
gcc Bugzilla search (was: Casting the return value of ...) Michael S <already5chosen@yahoo.com> - 2024-03-29 16:01 +0200
Re: gcc Bugzilla search David Brown <david.brown@hesbynett.no> - 2024-03-29 17:00 +0100
Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 15:37 -0700
Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-06-07 21:23 -0700
Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-29 14:06 +0100
Re: Casting the return value of ... "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2024-03-29 15:46 -0700
Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-29 13:58 +0100
Re: Casting the return value of ... bart <bc@freeuk.com> - 2024-03-29 13:32 +0000
Re: Casting the return value of ... David Brown <david.brown@hesbynett.no> - 2024-03-29 17:10 +0100
Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-03-30 02:32 -0700
Re: Casting the return value of ... bart <bc@freeuk.com> - 2024-03-30 11:14 +0000
Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-04-08 23:41 -0700
Re: Casting the return value of ... Andrey Tarasevich <andreytarasevich@hotmail.com> - 2024-03-28 21:41 -0700
Re: Casting the return value of ... Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2024-03-28 22:02 -0700
Re: Casting the return value of ... Tim Rentsch <tr.17687@z991.linuxsc.com> - 2024-03-29 15:52 -0700
Page 2 of 2 — ← Prev page 1 [2]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2024-03-29 17:00 +0100 |
| Subject | Re: gcc Bugzilla search |
| Message-ID | <uu6ojo$cm5h$1@dont-email.me> |
| In reply to | #384088 |
On 29/03/2024 15:01, Michael S wrote: > On Fri, 29 Mar 2024 15:53:10 +0200 > Michael S <already5chosen@yahoo.com> wrote: > >> On Thu, 28 Mar 2024 22:33:56 -0000 (UTC) >> Kaz Kylheku <433-929-6894@kylheku.com> wrote: >> >>> On 2024-03-28, Kaz Kylheku <433-929-6894@kylheku.com> wrote: >>>> On 2024-03-28, Kaz Kylheku <433-929-6894@kylheku.com> wrote: >>>>> Standard C does not say that any extensions are prohibited. >>>>> How silly to think so, and write about it, and code a facet of >>>>> the compiler diagnostic system that way! >>>>> >>>>> I'm actually opening a GCC bugzilla about this right now. >>>> >>>> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114526 >>> >>> Hilarious pushback ensues. >>> >> >> You got one commentator on your side. >> > > BTW, I tried to find out who are Harald van Dijk and Joseph S. Myers > (the post of the later sounds like one of insider) but failed. > Did gcc Bugzilla silently disabled "Search By People" option? > Or I am holding it wrong? > Joseph S. Myers is one of the major developers of GCC. I believe he is employed by Red Hat at the moment, and is the co-maintainer of the C front-end for GCC as well as a Release Manager. He is also involved in the C standards themselves and has represented the UK at C standards meetings. He is regularly on the gcc mailing lists, and in discussions on bugzilla. Basically, he is one of the "big guns" in GCC. (I don't know Harald van Dijk.)
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2024-03-28 15:37 -0700 |
| Message-ID | <877chmt23h.fsf@nosuchdomain.example.com> |
| In reply to | #384073 |
Kaz Kylheku <433-929-6894@kylheku.com> writes:
> On 2024-03-28, Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
>> The warnings I get from gcc are:
>>
>> warning: ISO C forbids conversion of function pointer to object pointer type [-Wpedantic]
>> warning: ISO C forbids conversion of object pointer to function pointer type [-Wpedantic]
>>
>> With -pedantic-errors, these become fatal errors.
>>
>> I disagree with gcc. ISO C doesn't define the behavior, but it doesn't
>> forbid the conversion.
>
> It's never good for a diagnostic to be stating a blatant falsehood,
> regardless of whether the presence of the diagnostic is a good idea
> or not.
[...]
> I'm actually opening a GCC bugzilla about this right now.
I should have remembered that I reported this as a bug in 2017:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584
That bug report was closed (inappropriately IMHO) as a duplicate of
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11234
A commenter on bug #83584 cites the C99 Rationale:
"Even with an explicit cast, it is invalid to convert a function pointer
to an object pointer or a pointer to void, or vice versa."
It's not clear what "invalid" means in that context, and in any case the
Rationale is not normative.
N1570 Annex J 5.7 mentions casting between object pointers and function
pointers as a common extension.
Kaz, I see you've submitted
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114526
which has (inappropriately IMHO) been closed as a duplicate of #11234.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Medtronic
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2024-06-07 21:23 -0700 |
| Message-ID | <86plsskqp2.fsf@linuxsc.com> |
| In reply to | #384073 |
Kaz Kylheku <433-929-6894@kylheku.com> writes: [gcc documentation talks about "forbidden extensions"] > The misconception is repeated in the GNU Conding Conventions. It might > have come from the same person. > > https://www.gnu.org/prep/standards/standards.html > > But we do not follow either of these specifications rigidly, and > there are specific points on which we decided not to follow them, so > as to make the GNU system better for users. > > For instance, Standard C says that nearly all extensions to C are > prohibited. How silly! GCC implements many extensions, some of which > were later adopted as part of the standard. If you want these > constructs to give an error message as ?required? by the standard, > you must specify ?--pedantic?, which was implemented only so that we > can say ?GCC is a 100% implementation of the standard?, not because > there is any reason to actually use it. > > Standard C does not say that any extensions are prohibited. > How silly to think so, and write about it, and code a facet of the > compiler diagnostic system that way! Probably the people who wrote the gcc documentation mean something different by the word "extension" than the C standard does. It's not a good idea to do that, but it does provide a plausible explanation for why they wrote what they did.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2024-03-29 14:06 +0100 |
| Message-ID | <uu6edi$a076$2@dont-email.me> |
| In reply to | #384071 |
On 28/03/2024 22:07, Keith Thompson wrote: > bart <bc@freeuk.com> writes: >> On 28/03/2024 19:38, Keith Thompson wrote: >>> Kaz Kylheku <433-929-6894@kylheku.com> writes: >>> [...] >>>> Conversions between function pointers and data pointers are an >>>> extension; it is not well-defined behavior in ISO C. >>>> >>>> Therefore we can neither say that ISO C doesn't require a cast there (it >>>> imposes no requirements at all), nor that the conversion is fine with a >>>> cast. >>>> >>>> The cast is /likely/ necessary, in order to correctly trigger the >>>> extension. >>> ISO C does require a cast. The cast is necessary to avoid a >>> constraint violation and a mandatory diagnostic. The resulting >>> behavior is undefined in ISO C, but defined by POSIX. Assigning a >>> void* value to a pointer-to-function object without a cast violates >>> the constraint for simple assignment (N1570 6.5.16.1p1). >> >> What would such a cast look like? Since this gives a warning with >> -Wpedantic even with a cast: >> >> void* p; >> void(*q)(void); >> >> p=(void*)q; >> q=(void(*)(void))p; > > The warnings I get from gcc are: > > warning: ISO C forbids conversion of function pointer to object pointer type [-Wpedantic] > warning: ISO C forbids conversion of object pointer to function pointer type [-Wpedantic] > > With -pedantic-errors, these become fatal errors. > > I disagree with gcc. ISO C doesn't define the behavior, but it doesn't > forbid the conversion. (Anyone who disagrees is invited to cite the > constraint that it violates.) > I think that the C standards don't forbid the conversion, but the description of pointer conversions (6.3.2.3) does not describe such conversions. That makes it, AFAICS, undefined behaviour rather than "forbidden" (which I would define as something that mandates a diagnostic). Dereferencing such converted pointers might be undefined behaviour (if you haven't converted back to the original type), or implementation-dependent behaviour (if the conversions change the bitwise representation of the pointer). I personally think it's good that gcc has this diagnostic, even if the message text is not strictly accurate. > Note that clang doesn't issue this diagnostic. >
[toc] | [prev] | [next] | [standalone]
| From | "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> |
|---|---|
| Date | 2024-03-29 15:46 -0700 |
| Message-ID | <uu7gcl$i87d$1@dont-email.me> |
| In reply to | #384084 |
On 3/29/2024 6:06 AM, David Brown wrote: > On 28/03/2024 22:07, Keith Thompson wrote: >> bart <bc@freeuk.com> writes: >>> On 28/03/2024 19:38, Keith Thompson wrote: >>>> Kaz Kylheku <433-929-6894@kylheku.com> writes: >>>> [...] >>>>> Conversions between function pointers and data pointers are an >>>>> extension; it is not well-defined behavior in ISO C. >>>>> >>>>> Therefore we can neither say that ISO C doesn't require a cast >>>>> there (it >>>>> imposes no requirements at all), nor that the conversion is fine >>>>> with a >>>>> cast. >>>>> >>>>> The cast is /likely/ necessary, in order to correctly trigger the >>>>> extension. >>>> ISO C does require a cast. The cast is necessary to avoid a >>>> constraint violation and a mandatory diagnostic. The resulting >>>> behavior is undefined in ISO C, but defined by POSIX. Assigning a >>>> void* value to a pointer-to-function object without a cast violates >>>> the constraint for simple assignment (N1570 6.5.16.1p1). >>> >>> What would such a cast look like? Since this gives a warning with >>> -Wpedantic even with a cast: >>> >>> void* p; >>> void(*q)(void); >>> >>> p=(void*)q; >>> q=(void(*)(void))p; >> >> The warnings I get from gcc are: >> >> warning: ISO C forbids conversion of function pointer to object >> pointer type [-Wpedantic] >> warning: ISO C forbids conversion of object pointer to function >> pointer type [-Wpedantic] >> >> With -pedantic-errors, these become fatal errors. >> >> I disagree with gcc. ISO C doesn't define the behavior, but it doesn't >> forbid the conversion. (Anyone who disagrees is invited to cite the >> constraint that it violates.) >> > > I think that the C standards don't forbid the conversion, but the > description of pointer conversions (6.3.2.3) does not describe such > conversions. That makes it, AFAICS, undefined behaviour rather than > "forbidden" (which I would define as something that mandates a diagnostic). Agreed. Its undefined behavior wrt std C, however, _not_ when it comes to POSIX. > > Dereferencing such converted pointers might be undefined behaviour (if > you haven't converted back to the original type), or > implementation-dependent behaviour (if the conversions change the > bitwise representation of the pointer). > > I personally think it's good that gcc has this diagnostic, even if the > message text is not strictly accurate. > > >> Note that clang doesn't issue this diagnostic. >> >
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2024-03-29 13:58 +0100 |
| Message-ID | <uu6dtk$a076$1@dont-email.me> |
| In reply to | #384070 |
On 28/03/2024 21:30, bart wrote:
> On 28/03/2024 19:38, Keith Thompson wrote:
>> Kaz Kylheku <433-929-6894@kylheku.com> writes:
>> [...]
>>> Conversions between function pointers and data pointers are an
>>> extension; it is not well-defined behavior in ISO C.
>>>
>>> Therefore we can neither say that ISO C doesn't require a cast there (it
>>> imposes no requirements at all), nor that the conversion is fine with a
>>> cast.
>>>
>>> The cast is /likely/ necessary, in order to correctly trigger the
>>> extension.
>>
>> ISO C does require a cast. The cast is necessary to avoid a constraint
>> violation and a mandatory diagnostic. The resulting behavior is
>> undefined in ISO C, but defined by POSIX.
>>
>> Assigning a void* value to a pointer-to-function object without a cast
>> violates the constraint for simple assignment (N1570 6.5.16.1p1).
>
> What would such a cast look like? Since this gives a warning with
> -Wpedantic even with a cast:
>
> void* p;
> void(*q)(void);
>
> p=(void*)q;
> q=(void(*)(void))p;
>
>
One method that silences all gcc warnings here is to cast via uintptr_t:
#include <stdint.h>
void* p;
void(*q)(void);
typedef void(*FVoid)(void);
void foo(void) {
p = (void*) (uintptr_t) q;
}
void bar(void) {
q = (FVoid) (uintptr_t) p;
}
I think it is good to have the gcc warnings enabled to help catch
mistakes, and you then need to make special effort when doing something
odd - hence the casts. (On any POSIX system where casting between
pointer-to-function and pointer-to-object types can work, uintptr_t will
exist and the cast here will not affect the value of the pointer.)
[toc] | [prev] | [next] | [standalone]
| From | bart <bc@freeuk.com> |
|---|---|
| Date | 2024-03-29 13:32 +0000 |
| Message-ID | <uu6fss$agvi$1@dont-email.me> |
| In reply to | #384083 |
On 29/03/2024 12:58, David Brown wrote:
> On 28/03/2024 21:30, bart wrote:
>> On 28/03/2024 19:38, Keith Thompson wrote:
>>> Kaz Kylheku <433-929-6894@kylheku.com> writes:
>>> [...]
>>>> Conversions between function pointers and data pointers are an
>>>> extension; it is not well-defined behavior in ISO C.
>>>>
>>>> Therefore we can neither say that ISO C doesn't require a cast there
>>>> (it
>>>> imposes no requirements at all), nor that the conversion is fine with a
>>>> cast.
>>>>
>>>> The cast is /likely/ necessary, in order to correctly trigger the
>>>> extension.
>>>
>>> ISO C does require a cast. The cast is necessary to avoid a constraint
>>> violation and a mandatory diagnostic. The resulting behavior is
>>> undefined in ISO C, but defined by POSIX.
>>>
>>> Assigning a void* value to a pointer-to-function object without a cast
>>> violates the constraint for simple assignment (N1570 6.5.16.1p1).
>>
>> What would such a cast look like? Since this gives a warning with
>> -Wpedantic even with a cast:
>>
>> void* p;
>> void(*q)(void);
>>
>> p=(void*)q;
>> q=(void(*)(void))p;
>>
>>
>
> One method that silences all gcc warnings here is to cast via uintptr_t:
>
> #include <stdint.h>
>
> void* p;
> void(*q)(void);
>
> typedef void(*FVoid)(void);
>
> void foo(void) {
> p = (void*) (uintptr_t) q;
> }
>
> void bar(void) {
> q = (FVoid) (uintptr_t) p;
> }
I was aware of the double conversion but KT used 'a cast' so I wondered
if there was a single cast that could be used.
It is odd however that function and object pointers can be considered so
different that even an explicit conversion between them is deemed to be
meaningless.
Yet converting either to and from an integer type is perfectly fine,
even though it isn't even a pointer type!
I wonder then why a conversion between function and object couldn't be
implemented, internally, via such an intermediate integer type anyway.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2024-03-29 17:10 +0100 |
| Message-ID | <uu6p4t$cm5h$2@dont-email.me> |
| In reply to | #384086 |
On 29/03/2024 14:32, bart wrote:
> On 29/03/2024 12:58, David Brown wrote:
>> On 28/03/2024 21:30, bart wrote:
>>> On 28/03/2024 19:38, Keith Thompson wrote:
>>>> Kaz Kylheku <433-929-6894@kylheku.com> writes:
>>>> [...]
>>>>> Conversions between function pointers and data pointers are an
>>>>> extension; it is not well-defined behavior in ISO C.
>>>>>
>>>>> Therefore we can neither say that ISO C doesn't require a cast
>>>>> there (it
>>>>> imposes no requirements at all), nor that the conversion is fine
>>>>> with a
>>>>> cast.
>>>>>
>>>>> The cast is /likely/ necessary, in order to correctly trigger the
>>>>> extension.
>>>>
>>>> ISO C does require a cast. The cast is necessary to avoid a constraint
>>>> violation and a mandatory diagnostic. The resulting behavior is
>>>> undefined in ISO C, but defined by POSIX.
>>>>
>>>> Assigning a void* value to a pointer-to-function object without a cast
>>>> violates the constraint for simple assignment (N1570 6.5.16.1p1).
>>>
>>> What would such a cast look like? Since this gives a warning with
>>> -Wpedantic even with a cast:
>>>
>>> void* p;
>>> void(*q)(void);
>>>
>>> p=(void*)q;
>>> q=(void(*)(void))p;
>>>
>>>
>>
>> One method that silences all gcc warnings here is to cast via uintptr_t:
>>
>> #include <stdint.h>
>>
>> void* p;
>> void(*q)(void);
>>
>> typedef void(*FVoid)(void);
>>
>> void foo(void) {
>> p = (void*) (uintptr_t) q;
>> }
>>
>> void bar(void) {
>> q = (FVoid) (uintptr_t) p;
>> }
>
> I was aware of the double conversion but KT used 'a cast' so I wondered
> if there was a single cast that could be used.
A single cast is all that is needed as far as the C standards are
concerned, but the double cast is helpful to silence the gcc warning.
(I agree with Keith that a diagnostic is not required by the C
standards, and thus the warning message and the choice of flag to
control it are inaccurate, but I think it is a useful warning to have
enabled in general.)
>
> It is odd however that function and object pointers can be considered so
> different that even an explicit conversion between them is deemed to be
> meaningless.
>
Why? They are such totally different concepts in C. It does not make
sense, within the semantics of C, to consider functions as data or data
as functions.
It can make sense in a wider context, outside of the things defined in
the C standards, and it is useful that you can make such conversions
with real C compilers (since the C standards don't cover /everything/ of
interest to programmers).
But it seems very reasonable to me to say that programmers have to go
out of their way to mix functions and data like this - it is a good
thing that awkward, rare and inherently risky things are harder to write
and come with warnings.
> Yet converting either to and from an integer type is perfectly fine,
> even though it isn't even a pointer type!
I'd be happy if C required a bit more effort for converting back and
forth between pointers and integer types - the ease here is for historic
reasons, I think. But at least it needs a cast.
>
> I wonder then why a conversion between function and object couldn't be
> implemented, internally, via such an intermediate integer type anyway.
>
I'm sure it could.
I don't see such pointer conversions having wide-spread use, and thus
don't see any reason to make them easier. Cases such as "dlsym" are
rare, and any required ugly conversions can be neatly contained within
the function.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2024-03-30 02:32 -0700 |
| Message-ID | <86plvchxpn.fsf@linuxsc.com> |
| In reply to | #384086 |
bart <bc@freeuk.com> writes:
> On 29/03/2024 12:58, David Brown wrote:
>
>> On 28/03/2024 21:30, bart wrote:
>>
>>> On 28/03/2024 19:38, Keith Thompson wrote:
>>>
>>>> Kaz Kylheku <433-929-6894@kylheku.com> writes:
>>>> [...]
>>>>
>>>>> Conversions between function pointers and data pointers are an
>>>>> extension; it is not well-defined behavior in ISO C.
>>>>>
>>>>> Therefore we can neither say that ISO C doesn't require a cast
>>>>> there (it imposes no requirements at all), nor that the
>>>>> conversion is fine with a cast.
>>>>>
>>>>> The cast is /likely/ necessary, in order to correctly trigger
>>>>> the extension.
>>>>
>>>> ISO C does require a cast. The cast is necessary to avoid a
>>>> constraint violation and a mandatory diagnostic. The resulting
>>>> behavior is undefined in ISO C, but defined by POSIX.
>>>>
>>>> Assigning a void* value to a pointer-to-function object without a
>>>> cast violates the constraint for simple assignment (N1570
>>>> 6.5.16.1p1).
>>>
>>> What would such a cast look like? Since this gives a warning with
>>> -Wpedantic even with a cast:
>>>
>>> void* p;
>>> void(*q)(void);
>>>
>>> p=(void*)q;
>>> q=(void(*)(void))p;
>>
>> One method that silences all gcc warnings here is to cast via
>> uintptr_t:
>>
>> #include <stdint.h>
>>
>> void* p;
>> void(*q)(void);
>>
>> typedef void(*FVoid)(void);
>>
>> void foo(void) {
>> p = (void*) (uintptr_t) q;
>> }
>>
>> void bar(void) {
>> q = (FVoid) (uintptr_t) p;
>> }
>
> I was aware of the double conversion but KT used 'a cast' so I
> wondered if there was a single cast that could be used.
There is not, if it's important that it work reliably across
different compilers and different platforms.
> It is odd however that function and object pointers can be
> considered so different that even an explicit conversion
> between them is deemed to be meaningless.
Function pointers and object pointers don't have to be the same
size, or use the same form of representation. The C standard
allows implementations where code and data live in completely
separate memories. In such cases there is no sensible way to
convert between the two kinds of pointers, because the two kinds
of addresses have no relationship to each other.
> Yet converting either to and from an integer type is perfectly
> fine, even though it isn't even a pointer type!
Converting to an integer type might be okay but it doesn't have
to be. The C standard says this explicitly:
Any pointer type may be converted to an integer type. Except
as previously specified, the result is implementation-defined.
If the result cannot be represented in the integer type, the
behavior is undefined. The result need not be in the range of
values of any integer type.
Note in particular the last sentence.
> I wonder then why a conversion between function and object
> couldn't be implemented, internally, via such an intermediate
> integer type anyway.
On platforms where object pointers and function pointers both
point into the same address space, converting between the two
kinds of pointers could be implemented internally just by
copying the bits, without having to go through some integer
intermediate. Indeed I expect that implementations that
support the extension of converting between the two kinds
of pointers do just that. But there is no guarantee this
kind of approach will work on other platforms. Because the
C standard is meant to apply to platforms where function
pointers and object pointers have no relationship to each
other, the C standard does not give permission to convert
between them.
[toc] | [prev] | [next] | [standalone]
| From | bart <bc@freeuk.com> |
|---|---|
| Date | 2024-03-30 11:14 +0000 |
| Message-ID | <uu8s6n$v2o8$2@dont-email.me> |
| In reply to | #384100 |
On 30/03/2024 09:32, Tim Rentsch wrote: > bart <bc@freeuk.com> writes: >> I was aware of the double conversion but KT used 'a cast' so I >> wondered if there was a single cast that could be used. > > There is not, if it's important that it work reliably across > different compilers and different platforms. > >> It is odd however that function and object pointers can be >> considered so different that even an explicit conversion >> between them is deemed to be meaningless. > > Function pointers and object pointers don't have to be the same > size, or use the same form of representation. The C standard > allows implementations where code and data live in completely > separate memories. In such cases there is no sensible way to > convert between the two kinds of pointers, because the two kinds > of addresses have no relationship to each other. Suppose a object pointer is 32 bits, and a function pointer is a 32-byte descriptor. An implementation could choose to present a function pointer as a 32-bit object pointer, which points to the full 32-byte descriptor in data memory. The simplest way of doing that is to have, for each function (or each one whose address is taken), a fixed corresponding descriptor in data memory. So here function and object pointers can be exactly the same size, and can both refer to data memory, as far as the programmer is concerned. Dereferencing such a function pointer, to call the function, will involve an extra bit of indirection. It would need something extra anyway to deal with those 32 bytes.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2024-04-08 23:41 -0700 |
| Message-ID | <86bk6j2g2c.fsf@linuxsc.com> |
| In reply to | #384104 |
bart <bc@freeuk.com> writes:
> On 30/03/2024 09:32, Tim Rentsch wrote:
>
>> bart <bc@freeuk.com> writes:
>>
>>> I was aware of the double conversion but KT used 'a cast' so I
>>> wondered if there was a single cast that could be used.
>>
>> There is not, if it's important that it work reliably across
>> different compilers and different platforms.
>>
>>> It is odd however that function and object pointers can be
>>> considered so different that even an explicit conversion
>>> between them is deemed to be meaningless.
>>
>> Function pointers and object pointers don't have to be the same
>> size, or use the same form of representation. The C standard
>> allows implementations where code and data live in completely
>> separate memories. In such cases there is no sensible way to
>> convert between the two kinds of pointers, because the two kinds
>> of addresses have no relationship to each other.
>
> Suppose a object pointer is 32 bits, and a function pointer is a
> 32-byte descriptor.
>
> An implementation could choose to present a function pointer as a
> 32-bit object pointer, which points to the full 32-byte descriptor in
> data memory.
>
> The simplest way of doing that is to have, for each function (or each
> one whose address is taken), a fixed corresponding descriptor in data
> memory. So here function and object pointers can be exactly the same
> size, and can both refer to data memory, as far as the programmer is
> concerned.
>
> Dereferencing such a function pointer, to call the function, will
> involve an extra bit of indirection. It would need something extra
> anyway to deal with those 32 bytes.
Two problems. One, even if the proposed scheme is workable in some
cases that doesn't mean it will be in all cases. Two, it imposes
what may be a significant cost but offers essentially no benefit.
The only useful thing that can be done with a converted function
pointer is cast it to an appropriate function pointer type so that
the function can be called. If someone wants to have values and
variables that can hold both object pointers and function pointers
it is easy enough to do that by using a union:
typedef union { void *pv; void (*pf)(); } VorF;
with no hidden implementation machinery needed. There is no good
reason to gussy up the language or have implementations jump
through hoops when the needed capability is already present in
the language as it is now (and has been for more than 30 years).
[toc] | [prev] | [next] | [standalone]
| From | Andrey Tarasevich <andreytarasevich@hotmail.com> |
|---|---|
| Date | 2024-03-28 21:41 -0700 |
| Message-ID | <uu5gpa$3mm6$1@dont-email.me> |
| In reply to | #384057 |
On 03/28/24 8:09 AM, Kenny McCormack wrote: > > But here's the thing. Is the casting of the result of dlsym() necessary? > Isn't this the same as "casting the return value of malloc()", where you > don't need to cast it since it auto-magically gets casted by being assigned > to the thing on the left of the assignment? No, it isn't even remotely the same. C language allows implicit casts from any object pointer type to `void *` and vice-versa. Which is why casting the result of `malloc` is unnecessary. C language does not support implicit casts between object pointer types (like `void *`) and function pointer types. Moreover, C language still does not support _explicit_ casts between `void *` and function pointer types either. POSIX guarantees/requirements are not C. > And why do we even need the "clumsy" cast? Why not just: > > cosine = dlsym(handle, "cos"); Because this is a constraint violation, aka a "compile error". -- Best regards, Andrey
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2024-03-28 22:02 -0700 |
| Message-ID | <87r0ftsk9g.fsf@nosuchdomain.example.com> |
| In reply to | #384078 |
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
[...]
> No, it isn't even remotely the same. C language allows implicit casts
> from any object pointer type to `void *` and vice-versa. Which is why
> casting the result of `malloc` is unnecessary.
To be picky, there are no "implicit casts". There are implicit
conversions. A cast is an explicit conversion.
> C language does not support implicit casts between object pointer
> types (like `void *`) and function pointer types. Moreover, C language
> still does not support _explicit_ casts between `void *` and function
> pointer types either. POSIX guarantees/requirements are not C.
It "does not support" them in the sense that it does not define their
behavior. Such a cast does not violate any constraint, and an
implementation or third-party standard is free to define the semantics.
By contrast, conversions between floating types and pointer types are
constraint violations.
[...]
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Medtronic
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <tr.17687@z991.linuxsc.com> |
|---|---|
| Date | 2024-03-29 15:52 -0700 |
| Message-ID | <8634s8k5wp.fsf@linuxsc.com> |
| In reply to | #384057 |
gazelle@shell.xmission.com (Kenny McCormack) writes:
[some white space added or deleted]
> I think this is a variation on that old CLC standard "Why you should not
> cast the return value of malloc()".
>
> Caution: POSIX (non-strict ISO) stuff coming up. If this bothers you,
> please hit "next" right now.
>
> I frequently write "interposer" functions as shared libraries (on Linux).
> Generally, this requires using dlsym() and RTLD_NEXT to get a pointer to the
> "real" function, so that you can call that as part of your interposer
> routine. I have always done it like this (e.g., for a function returning
> char *, taking 2 size_t args - just to pick an arbitrary example to make
> things more concrete):
>
> char *someFunction(size_t,size_t) {
> static char * (*real_someFunction) (size_t,size_t);
>
> if (!real_someFunction)
> real_someFunction =
> (char * (*real_someFunction) (size_t,size_t))
> dlsym(RTLD_NEXT,"someFunction");
> ...
> }
Presumably you meant (char * (*)(size_t,size_t)) for the type used
in the cast.
> This works fine (and compiles clean with the usual -W -Wall -Werror).
Did you also try with -pedantic or -pedantic-errors? If not then
it's a good idea to include it. Even if you don't use -pedantic all
the time, it's a good idea to include it occasionally, especially in
cases like this where you want to understand more about what is
going on.
> But here's the thing. Is the casting of the result of dlsym() necessary?
> Isn't this the same as "casting the return value of malloc()", where you
> don't need to cast it since it auto-magically gets casted by being assigned
> to the thing on the left of the assignment?
There are a couple of reasons why this doesn't work, and also why
it isn't a good idea. More explanation below.
> Note that it is duplicative, having to specify the type info for the
> function pointer twice - once in the declaration of the pointer and
> then again in the dlsym() call. It'd be better (in terms of
> maintenance) if you only had to do it once.
Certainly it is inconvenient to give a long and complicated type (or
type name) multiple times. Typically most of the inconvenience is
avoided by using a typedef, as for example
typedef char *SomeF( size_t, size_t );
static SomeF *f_pointer;
...
f_pointer = (SomeF *)( ... );
I should add that this construction doesn't help in the dlsym()
situation, but it illustrates the principle of using typedef.
> But here's where it gets interesting. In the man page for dlopen(), we
> find this example code and a long detailed comment:
>
> double (*cosine)(double);
> ...
> cosine = (double (*)(double)) dlsym(handle, "cos");
>
> /* According to the ISO C standard, casting between function
> pointers and 'void *', as done above, produces undefined results.
> POSIX.1-2003 and POSIX.1-2008 accepted this state of affairs and
> proposed the following workaround:
>
> *(void **) (&cosine) = dlsym(handle, "cos");
>
> This (clumsy) cast conforms with the ISO C standard and will
> avoid any compiler warnings.
>
> The 2013 Technical Corrigendum to POSIX.1-2008 (a.k.a.
> POSIX.1-2013) improved matters by requiring that conforming
> implementations support casting 'void *' to a function pointer.
> Nevertheless, some compilers (e.g., gcc with the '-pedantic'
> option) may complain about the cast used in this program. */
>
> So, they seem to think the cast is necessary - or at least a good idea,
> Are they right?
They are right in the important sense that using a straightforward
cast is the wrong way to tackle this problem. The "solution" given
above is ill advised because it strays into the realm of undefined
behavior. But the key point is correct. A fix for how to address
the problem is given below.
> And why do we even need the "clumsy" cast? Why not just:
>
> cosine = dlsym(handle, "cos");
The C standard does not consider function pointers and object
pointers to be inter-convertible. Because of that, there is no
reason to allow a void * pointer to be assigned to a variable
that has a function pointer type.
Returning to your original scenario, here is a way to do what you
want that stays inside the ISO C limits, and so avoids the problem
mentioned in the dlopen() man page:
/* presume there is a declaration for dlsym() available */
char *
outerFunction( size_t a, size_t b ){
typedef char *SF_f( size_t, size_t ); // an actual function type
extern SF_f outerFunction; // verify type compatibility
static SF_f *dynamic_f; // pointer to dynamically loaded f
if( ! dynamic_f ){
union { void *v; SF_f *f; } it = { dlsym( 0, "someFunction" ) };
dynamic_f = it.f;
// we might want to check that dynamic_f is not null now
}
return dynamic_f( a, b );
}
This code compiles cleanly as C99 or C11, under both gcc and clang,
with a full set of restrictive diagnostics: -Wall -Wextra -Werror
and -pedantic-errors. (A simple change will allow it to compile,
and compile cleanly, as C90 if that is desired.)
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | comp.lang.c
csiph-web