Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #93474 > unrolled thread
| Started by | Thiago Adams <thiago.adams@gmail.com> |
|---|---|
| First post | 2016-09-14 12:01 -0700 |
| Last post | 2016-09-15 11:23 -0700 |
| Articles | 20 on this page of 99 — 14 participants |
Back to article view | Back to comp.lang.c
Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 12:01 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 13:15 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 13:27 -0700
Re: Sugestions for runtime polymorphism Richard Heathfield <rjh@cpax.org.uk> - 2016-09-14 21:50 +0100
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 14:20 -0700
Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-14 17:32 -0400
Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-14 16:30 -0700
Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-14 17:54 -0400
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 17:34 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 17:58 -0700
Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-14 19:50 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 05:03 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-15 10:43 +0100
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 05:29 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-15 19:49 +0100
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 11:58 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-15 20:29 +0100
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 14:00 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-16 07:27 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-16 16:34 +0100
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-16 09:36 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-20 12:59 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-20 14:08 -0700
Re: Sugestions for runtime polymorphism Ian Collins <ian-news@hotmail.com> - 2016-09-21 15:53 +1200
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-21 07:38 -0700
Re: Sugestions for runtime polymorphism Ian Collins <ian-news@hotmail.com> - 2016-09-23 09:12 +1200
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-21 05:26 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-21 05:35 -0700
Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-21 06:01 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-22 01:44 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-22 13:16 +0100
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-22 08:02 -0700
Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-22 11:44 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-22 09:52 -0700
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-23 09:49 +0200
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-23 07:55 -0700
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-24 16:29 +0200
Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-24 15:56 +0100
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-24 17:50 +0200
Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-24 13:45 -0400
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-24 11:26 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 10:38 -0700
Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-24 21:03 +0100
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 12:43 +0200
Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-25 11:48 -0400
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 18:39 +0200
Re: Sugestions for runtime polymorphism "James R. Kuyper" <jameskuyper@verizon.net> - 2016-09-25 13:14 -0400
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-25 13:47 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 10:39 -0700
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 23:25 +0200
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-25 13:10 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-25 12:55 -0700
Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-25 20:38 +0100
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 23:20 +0200
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 07:15 -0700
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-28 21:29 +0200
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-24 10:52 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-24 10:33 -0700
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-25 12:46 +0200
Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-24 13:58 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-28 04:46 -0700
Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-24 00:07 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-23 08:52 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-23 09:56 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-23 12:00 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-22 08:45 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-22 09:36 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-23 12:06 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-23 15:29 -0700
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-29 07:56 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-30 10:54 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-30 11:18 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-30 19:26 +0100
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-30 12:41 -0700
Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-09-30 21:07 +0100
Re: Sugestions for runtime polymorphism Malcolm McLean <malcolm.mclean5@btinternet.com> - 2016-09-30 23:30 -0700
Re: Sugestions for runtime polymorphism Ben Bacarisse <ben.usenet@bsb.me.uk> - 2016-10-01 11:35 +0100
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-10-01 14:44 -0700
Re: Sugestions for runtime polymorphism Richard Heathfield <rjh@cpax.org.uk> - 2016-09-14 22:56 +0100
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-15 13:19 +0200
Re: Sugestions for runtime polymorphism James Kuyper <jameskuyper@verizon.net> - 2016-09-15 08:07 -0400
Re: Sugestions for runtime polymorphism David Brown <david.brown@hesbynett.no> - 2016-09-15 14:24 +0200
Re: Sugestions for runtime polymorphism Richard Heathfield <rjh@cpax.org.uk> - 2016-09-15 15:34 +0100
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-15 05:10 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-15 09:12 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-14 23:32 +0100
Re: Sugestions for runtime polymorphism "Chris M. Thomasson" <invalid@invalid.invalid> - 2016-09-14 17:35 -0700
Re: Sugestions for runtime polymorphism Ian Collins <ian-news@hotmail.com> - 2016-09-15 16:24 +1200
Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-15 10:31 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-14 22:53 +0100
Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-14 16:56 -0700
Re: Sugestions for runtime polymorphism supercat@casperkitty.com - 2016-09-14 15:58 -0700
Re: Sugestions for runtime polymorphism Keith Thompson <kst-u@mib.org> - 2016-09-14 18:49 -0700
Re: Sugestions for runtime polymorphism luser droog <luser.droog@gmail.com> - 2016-09-14 14:17 -0700
Re: Sugestions for runtime polymorphism Thiago Adams <thiago.adams@gmail.com> - 2016-09-14 14:25 -0700
Re: Sugestions for runtime polymorphism luser droog <luser.droog@gmail.com> - 2016-09-14 14:40 -0700
Re: Sugestions for runtime polymorphism luser droog <luser.droog@gmail.com> - 2016-09-14 14:57 -0700
Re: Sugestions for runtime polymorphism BartC <bc@freeuk.com> - 2016-09-14 23:10 +0100
Re: Sugestions for runtime polymorphism Tim Rentsch <txr@alumni.caltech.edu> - 2016-09-15 11:23 -0700
Page 3 of 5 — ← Prev page 1 2 [3] 4 5 Next page →
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-09-24 11:26 -0700 |
| Message-ID | <85ffb276-ff44-44cb-b1c9-0844fe649ed3@googlegroups.com> |
| In reply to | #93985 |
On Saturday, September 24, 2016 at 12:45:56 PM UTC-5, James R. Kuyper wrote: > 4p2 says "Undefined behavior is otherwise indicated ... by the omission > of any explicit definition of the behavior". But you have to be careful > about applying that rule. Nowhere in the standard does it say explicitly > what the behavior of the expression 1+1 is if executed on Friday the > 13th at 13:13:13. However, it does say "The result of the binary + > operator is the sum of the operands.". That applies regardless of what > the values of the operands are, and regardless of the time of day. > Therefore, there is no "omission of any explicit definition", just > because there is no mention of Friday the 13th. The definition of the > behavior covers the possibility of time-dependent behavior by failing to > mention any time dependence, rendering time-dependent behavior > impermissible. I don't think anything in the Standard would forbid an implementation from having right-shifts of negative values use sign extension if __DATE__ identifies a Friday the 13th, or zero-fill on other days, if documentation for the implementation describes that behavior. The behavior of integer arithmetic, however, is rigidly specified by the Standard for additions that don't overflow, along with almost all cases, however. > That code accesses the object many times using an incompatible type, but > whenever it does so, it is writing a new value for the object. Those > accesses do not qualify as accessing the "stored value" of the object. > Every time that code accesses by reading the stored value, the read is > preceded by a write to that object through an lvalue of the same type as > the read. For an object with no declared type (which is what you create > by calling malloc()), the effective type is always the same as the type > of the last write to that memory through an lvalue that is not of > character type. Yup. > <pedantic> > There is one obscure case which is not covered by the first item on > 6.5p7's list. If CHAR_BIT==64, it's possible for T2 to be a character > type. As a result, the effective type would only change as a result of > writing through lvalues with type T1. In that case, the first item on > the list for 6.5p7 doesn't apply when reading through lvalues of type > T2. Instead, the sixth item on that list applies: "a character type", > since that's what T2 is in that case. > </pedantic> Even in that obscure case, behavior would still be defined--if an object has no declared type, writing it via character-type pointer will unset any pre-existing Effective Type (since operations that set the ET only do so until the next time an object is modified) and leave the object with no effective type (I'm assuming the horrible "copied as an array of character type" language--whatever that means--isn't applicable here) and consequently can be read as any type.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2016-09-28 10:38 -0700 |
| Message-ID | <kfneg43c4cd.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #93987 |
supercat@casperkitty.com writes: > [...] if an object > has no declared type, writing it via character-type pointer will unset > any pre-existing Effective Type (since operations that set the ET only > do so until the next time an object is modified) and leave the object > with no effective type [...] I believe this is a misreading. If an object with no declared type is written through a non-character type, "the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value." There is nothing that says that effective type stops being in force when a value is stored using a character type, that just isn't the effective type for the store access. For reads after the through-character-type store is done, those are subsequent to the previous non-character-type store, and so have that type as their effective type. The Standard doesn't say anything about "erasing" an effective type.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-09-24 21:03 +0100 |
| Message-ID | <87h995f4lm.fsf@bsb.me.uk> |
| In reply to | #93982 |
David Brown <david.brown@hesbynett.no> writes:
> On 24/09/16 16:56, Ben Bacarisse wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>
>>> On 23/09/16 16:55, supercat@casperkitty.com wrote:
<snip>
>>>> typedef long long T1;
>>>> typedef int64_t T2;
>>>> #define T1FMT "%lld"
>>>> #define T1VALUE 1
>>>> #define T2VALUE 2
>>>>
>>>> T1 blah3(void *p1, void *p2)
>>>> {
>>>> T1 *t1p, *t1p2;
>>>> T2 *t2p;
>>>> T1 temp;
>>>>
>>>> t1p = p1;
>>>> t2p = p2;
>>>> *t1p = T1VALUE; // Write as T1
>>>> *t2p = T2VALUE; // Write as T2
>>>> temp = *t2p; // Read as T2
>>>> t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
>>>> *t1p2 = temp; // Write as T1
>>>> return *t1p; // Read as T1
>>>> }
>>>>
>>>> T1 test3(void)
>>>> {
>>>> void *p = malloc(sizeof (T1) + sizeof (T2));
>>>> T1 result = blah3(p,p);
>>>> free(p);
>>>> return result;
>>>> }
<snip>
>>> If T1 and T2 are compatible types (as might be the case, such as on
>>> Windows), then the answer will be 2. If they are incompatible types,
>>> such as on 64-bit Linux, the answer is undefined - you are trying to
>>> access the same object through pointers to two incompatible types.
>>
>> That's not a thing! There are rules about how you can access objects,
>> but they are much more complex that this summary and I'm not sure where
>> you think the violation occurs. Can you point to the line and give the
>> rule being broken?
>
> I am thinking of the rules in 6.5, paragraph 7 about how "an object
> shall have its stored value accessed". It does not explicitly say
> that accessing the same data through pointers to incompatible types is
> undefined
In fact, it explicitly permits it in many ways, but I know you are not
talking about those permissions. More to the point, when paragraph 6 is
taken into account there are even more ways in which accesses to the
same data through pointers to incompatible types are permitted.
> - but it is implicitly undefined behaviour by virtue of not
> being defined behaviour.
If we ignore the initialisation of the two pointers (surely not at
issue) the code in question has only 9 object accesses, four of which
are simple mentions of a local object. Which one (or ones) of these 9,
fall foul (possibly by omission, if that is indeed the case) of the
rules in 6.5 p7? (The second sentence of paragraph 6 matters here too,
of course, to determine what the effective types are at each point in
the code.)
> But I could be wrong - and if this really is incorrect behaviour from
> gcc, then it needs reported and fixed.
And *I* could be wrong, but I've gone though all 9 object accesses and
every one appears to be explicitly permitted by p6 and p7 of section
6.5.
<snip>
>> My gcc (5.2.1 20151010) gives 2 for all -Ox. Presumably you have a
>> newer version?
>
> I am testing here with <https://gcc.godbolt.org/> for convenience. It
> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on
> gcc 4.7 onwards. gcc 4.5 and 4.6 give 2.
Including 5.2? My system is 64-bit Linux. (I could not see how to get
that site to show me the output.)
<snip>
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-09-25 12:43 +0200 |
| Message-ID | <ns89ok$lj2$1@dont-email.me> |
| In reply to | #93991 |
On 24/09/16 22:03, Ben Bacarisse wrote: > David Brown <david.brown@hesbynett.no> writes: <snip> >> But I could be wrong - and if this really is incorrect behaviour from >> gcc, then it needs reported and fixed. > > And *I* could be wrong, but I've gone though all 9 object accesses and > every one appears to be explicitly permitted by p6 and p7 of section > 6.5. > > <snip> >>> My gcc (5.2.1 20151010) gives 2 for all -Ox. Presumably you have a >>> newer version? >> >> I am testing here with <https://gcc.godbolt.org/> for convenience. It >> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on >> gcc 4.7 onwards. gcc 4.5 and 4.6 give 2. > > Including 5.2? My system is 64-bit Linux. (I could not see how to get > that site to show me the output.) > > <snip> > My test on gcc.godbolt.org is here: <https://gcc.godbolt.org/#compilers:!((compiler:g520,options:'-O2+-Wall+-Wextra+-x+c',sourcez:FAAjGIEsDsGMBsCuATApiAPAZwC7JjgHQAWAfKGCFHEmprgE4wDmJ5lVMCK62e8kAEZsKELrV658AexGiQOAJ4AHVGgBmIeNOjMtOvQBUAjAG55S1RpAEAbABYA%2BjhCGATOY7gNMdCYBiALKGIABEAKTw8Mih8t6o6r6uxgBqAIIAMgCqAKIgxgAMBXE%2B0H5u6dl5bkXA8iYggvAAhsQAzAAUAG7SkMggAFTKxgA0ID19g8puAJTyAN7yYA0DOMbKY6vrHkuuboM4bsqeHMkKqAC2x3WnCusgALwgwycch8qPzzu3Wx9PJpVcqZKAB6EEgADqTBw6GaWGSu1WR0%2B7kBOWBYDBkOhsPh7l2MKunyRx1uWIASqhmv04XsCdtPh0TAMZu8MViUpAsEJ4OUFNIzspetAYQwQLAdF1UAxuTpEWtpp9CaSOFioZAYSBaSZdgxUDhEAxoAd1hjVeDKdStXjjPIAL43SgNGG4ToTZBzDiLW7uqafC7NKLSWAdbkAL1Q0k0TOMMxAAGoQOHI9H3DMZq8ncYQHqsIh4C4nk1Wp0NsoM7t1HrUB1y5mwHqDUac6g8wXMw6OAQQAGYN1eh6FrsGrn84Xzq6OhXbsomCL1B1QoZiOhRwWbPDQskgoYxmucNPTo3DcaCmbKPagAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3> I changed the values of T1VALUE and T2VALUE to 100 and 200, to make it easier to spot them in the resulting assembly code. The details of the standards here is getting beyond me. When you and James both think the answer should be 1, and 2 is not allowed, then I am far from confident about 2 being allowable - you are both more better at "language lawyering" than me. But I do know that gcc will do this sort of transformation in practice, and in real code - you need to be very careful in mixing pointers to different integer types even when you know they are the same underlying hardware types. Maybe it's time to pass this on to the gcc mailing lists, and ask how they interpret it?
[toc] | [prev] | [next] | [standalone]
| From | "James R. Kuyper" <jameskuyper@verizon.net> |
|---|---|
| Date | 2016-09-25 11:48 -0400 |
| Message-ID | <c7e2e2a0-678b-292c-08db-0feab65420fe@verizon.net> |
| In reply to | #94018 |
On 09/25/2016 06:43 AM, David Brown wrote:
...
> My test on gcc.godbolt.org is here:
>
> <https://gcc.godbolt.org/#compilers:!((compiler:g520,options:'-O2+-Wall+-Wextra+-x+c',sourcez:FAAjGIEsDsGMBsCuATApiAPAZwC7JjgHQAWAfKGCFHEmprgE4wDmJ5lVMCK62e8kAEZsKELrV658AexGiQOAJ4AHVGgBmIeNOjMtOvQBUAjAG55S1RpAEAbABYA%2BjhCGATOY7gNMdCYBiALKGIABEAKTw8Mih8t6o6r6uxgBqAIIAMgCqAKIgxgAMBXE%2B0H5u6dl5bkXA8iYggvAAhsQAzAAUAG7SkMggAFTKxgA0ID19g8puAJTyAN7yYA0DOMbKY6vrHkuuboM4bsqeHMkKqAC2x3WnCusgALwgwycch8qPzzu3Wx9PJpVcqZKAB6EEgADqTBw6GaWGSu1WR0%2B7kBOWBYDBkOhsPh7l2MKunyRx1uWIASqhmv04XsCdtPh0TAMZu8MViUpAsEJ4OUFNIzspetAYQwQLAdF1UAxuTpEWtpp9CaSOFioZAYSBaSZdgxUDhEAxoAd1hjVeDKdStXjjPIAL43SgNGG4ToTZBzDiLW7uqafC7NKLSWAdbkAL1Q0k0TOMMxAAGoQOHI9H3DMZq8ncYQHqsIh4C4nk1Wp0NsoM7t1HrUB1y5mwHqDUac6g8wXMw6OAQQAGYN1eh6FrsGrn84Xzq6OhXbsomCL1B1QoZiOhRwWbPDQskgoYxmucNPTo3DcaCmbKPagAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3>
>
> I changed the values of T1VALUE and T2VALUE to 100 and 200, to make it
> easier to spot them in the resulting assembly code.
>
>
> The details of the standards here is getting beyond me. When you and
> James both think the answer should be 1, and 2 is not allowed, ...
I never said what the answer should be. Ben said gcc gave him 2 for all
optimization levels. I'm not sure why you think we've claimed the answer
should be 1.
Here's the original code that I was talking about, in order of execution:
main:
... test3();
test3:
void *p = malloc(sizeof (T1) + sizeof (T2));
/* p now points at a buffer; for convenience I'll refer to that buffer
using 'p' even in contexts where 'p' is not in scope.
*/
... blah3(p,p);
blah3:
T1 blah3(void *p1, void *p2)
{
/* p1 and p2 are both set equal to p */
t1p = p1;
t2p = p2;
/* t1p and t2p both point at the same location as p */
*t1p = T1VALUE; // Write as T1
/* The sizeof(T1) bytes starting at p now contain a representation of
T1VALUE as an object of type T1, which is now the effective type of
that memory.
*/
*t2p = T2VALUE; // Write as T2
/* The sizeof(T2) bytes starting at p now contain a representation of
T2VALUE as an object of type T2, which is now the effective type of
that memory.
*/
temp = *t2p; // Read as T2
/* Since *t2p has the type T2, which matches the effective type of that
memory, there is no problem reading the value T2VALUE from that
memory, which is then stored in temp.
*/
t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
/* I missed this point: conversion from T2* to T1* is allowed, since
this particular pointer is guaranteed to be correctly aligned for
either type. However, technically, the standard says nothing about
where t1p2 actually points. In principle, the only thing that is
guaranteed about the value of t1p2 is that if you convert it back to
T2*; the result will compare equal to t2p. For instance, the forward
conversion could add 1024 bytes to the position, so long as the reverse
conversion subtracted the same amount.
In practice, on virtually every real world implementation of C, t1p2
will point at the same location as all of the other object pointers in
this program, and I believe it was the committee's intent that this be
true. However, I haven't managed to convince anyone in authority that
there's any need to change the wording to reflect that intent.
*/
*t1p2 = temp; // Write as T1
/* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes
starting at p. The effective type of that memory is now T1.
*/
return *t1p; // Read as T1
/* *t1p has the type T1, matching the current effective type of that
memory. As a result, there's no problem retrieving T2VALUE from that
memory and returning it as the value of blah3.
*/
test3:
T1 result = blah3(p,p);
/* result now contains T2value */
free(p);
return result;
/* T2VALUE is now returned as the value of test3. */
main:
T1 result = test3();
/* result now has the value T2VALUE */
printf("The result is " T1FMT, result);
/* Which is then printed out */
T2VALUE is 2. By what argument would anyone claim that a value of 1
could be printed out?
> ... then I am
> far from confident about 2 being allowable - you are both more better at
> "language lawyering" than me. But I do know that gcc will do this sort
> of transformation in practice, and in real code - you need to be very
> careful in mixing pointers to different integer types even when you know
> they are the same underlying hardware types.
At no point does this code do anything which relies upon the assumption
that long long and int64_t are the same underlying type. It would work
equally well if T2 were any integer type other than _Bool. It would even
work if T2 were a floating point type, except for the theoretical
possibility of floating point roundoff errors, but in practice that
would never happen with integers smaller than 1.0/FLT_EPSILON.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-09-25 18:39 +0200 |
| Message-ID | <ns8ujt$qi8$1@dont-email.me> |
| In reply to | #94031 |
On 25/09/16 17:48, James R. Kuyper wrote:
> On 09/25/2016 06:43 AM, David Brown wrote:
> ...
>> My test on gcc.godbolt.org is here:
>>
>> <https://gcc.godbolt.org/#compilers:!((compiler:g520,options:'-O2+-Wall+-Wextra+-x+c',sourcez:FAAjGIEsDsGMBsCuATApiAPAZwC7JjgHQAWAfKGCFHEmprgE4wDmJ5lVMCK62e8kAEZsKELrV658AexGiQOAJ4AHVGgBmIeNOjMtOvQBUAjAG55S1RpAEAbABYA%2BjhCGATOY7gNMdCYBiALKGIABEAKTw8Mih8t6o6r6uxgBqAIIAMgCqAKIgxgAMBXE%2B0H5u6dl5bkXA8iYggvAAhsQAzAAUAG7SkMggAFTKxgA0ID19g8puAJTyAN7yYA0DOMbKY6vrHkuuboM4bsqeHMkKqAC2x3WnCusgALwgwycch8qPzzu3Wx9PJpVcqZKAB6EEgADqTBw6GaWGSu1WR0%2B7kBOWBYDBkOhsPh7l2MKunyRx1uWIASqhmv04XsCdtPh0TAMZu8MViUpAsEJ4OUFNIzspetAYQwQLAdF1UAxuTpEWtpp9CaSOFioZAYSBaSZdgxUDhEAxoAd1hjVeDKdStXjjPIAL43SgNGG4ToTZBzDiLW7uqafC7NKLSWAdbkAL1Q0k0TOMMxAAGoQOHI9H3DMZq8ncYQHqsIh4C4nk1Wp0NsoM7t1HrUB1y5mwHqDUac6g8wXMw6OAQQAGYN1eh6FrsGrn84Xzq6OhXbsomCL1B1QoZiOhRwWbPDQskgoYxmucNPTo3DcaCmbKPagAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3>
>>
>>
>> I changed the values of T1VALUE and T2VALUE to 100 and 200, to make it
>> easier to spot them in the resulting assembly code.
>>
>>
>> The details of the standards here is getting beyond me. When you and
>> James both think the answer should be 1, and 2 is not allowed, ...
>
> I never said what the answer should be. Ben said gcc gave him 2 for all
> optimization levels. I'm not sure why you think we've claimed the answer
> should be 1.
My apologies - I meant to say "think the answer should be /2/, and /1/
is not allowed". That was a rather unhelpful mixup on my part!
I should also have written "I think they think...", since it was my
interpretation of what you wrote, rather than your exact words.
>
> Here's the original code that I was talking about, in order of execution:
>
> main:
> ... test3();
>
> test3:
> void *p = malloc(sizeof (T1) + sizeof (T2));
> /* p now points at a buffer; for convenience I'll refer to that buffer
> using 'p' even in contexts where 'p' is not in scope.
> */
> ... blah3(p,p);
>
> blah3:
> T1 blah3(void *p1, void *p2)
> {
> /* p1 and p2 are both set equal to p */
> t1p = p1;
> t2p = p2;
> /* t1p and t2p both point at the same location as p */
> *t1p = T1VALUE; // Write as T1
> /* The sizeof(T1) bytes starting at p now contain a representation of
> T1VALUE as an object of type T1, which is now the effective type of
> that memory.
> */
> *t2p = T2VALUE; // Write as T2
> /* The sizeof(T2) bytes starting at p now contain a representation of
> T2VALUE as an object of type T2, which is now the effective type of
> that memory.
> */
> temp = *t2p; // Read as T2
> /* Since *t2p has the type T2, which matches the effective type of that
> memory, there is no problem reading the value T2VALUE from that
> memory, which is then stored in temp.
> */
OK so far...
> t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
> /* I missed this point: conversion from T2* to T1* is allowed, since
> this particular pointer is guaranteed to be correctly aligned for
> either type. However, technically, the standard says nothing about
> where t1p2 actually points. In principle, the only thing that is
> guaranteed about the value of t1p2 is that if you convert it back to
> T2*; the result will compare equal to t2p. For instance, the forward
> conversion could add 1024 bytes to the position, so long as the reverse
> conversion subtracted the same amount.
> In practice, on virtually every real world implementation of C, t1p2
> will point at the same location as all of the other object pointers in
> this program, and I believe it was the committee's intent that this be
> true. However, I haven't managed to convince anyone in authority that
> there's any need to change the wording to reflect that intent.
> */
gcc appears to be optimising on the basis that the only defined
behaviour for t1p2 is that you can covert it back to a T2* and get the
same pointer as t2p. The assembly it generates is (with my comments):
blah3:
movq $1, (%rdi) // Store 1 in *t1p
movl $1, %eax // The return value 1
movq $2, (%rsi) // Store 2 in *t2p
ret
test3:
movl $1, %eax
ret
> *t1p2 = temp; // Write as T1
> /* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes
> starting at p. The effective type of that memory is now T1.
> */
> return *t1p; // Read as T1
> /* *t1p has the type T1, matching the current effective type of that
> memory. As a result, there's no problem retrieving T2VALUE from that
> memory and returning it as the value of blah3.
> */
>
> test3:
> T1 result = blah3(p,p);
> /* result now contains T2value */
> free(p);
> return result;
> /* T2VALUE is now returned as the value of test3. */
>
> main:
> T1 result = test3();
> /* result now has the value T2VALUE */
> printf("The result is " T1FMT, result);
> /* Which is then printed out */
>
> T2VALUE is 2. By what argument would anyone claim that a value of 1
> could be printed out?
It is the result gcc gives.
This is either a valid result due to the conversion of pointer types
mentioned above (and claims about "virtually every real world
implementation of C" are simply incorrect, because gcc is a pretty major
exception), or gcc has a bug here.
To be clear, I would be happier if gcc gave 2 here - the same result as
other compilers on <gcc.godbolt.org>, and the result one would
reasonably expect. I would prefer if the C standards said that types
such as "long", "long long", and "int64_t" were all considered
"compatible" if they are all the same size (and similarly for "int",
"long", "int32_t"). Or at least, I would prefer it if gcc had this as
documented implementation-dependent behaviour.
The question is, is this a bug in gcc? Or is it just a case of
optimising from undefined behaviour in a way that might surprise people?
>
>> ... then I am
>> far from confident about 2 being allowable - you are both more better at
>> "language lawyering" than me. But I do know that gcc will do this sort
>> of transformation in practice, and in real code - you need to be very
>> careful in mixing pointers to different integer types even when you know
>> they are the same underlying hardware types.
>
> At no point does this code do anything which relies upon the assumption
> that long long and int64_t are the same underlying type. It would work
> equally well if T2 were any integer type other than _Bool. It would even
> work if T2 were a floating point type, except for the theoretical
> possibility of floating point roundoff errors, but in practice that
> would never happen with integers smaller than 1.0/FLT_EPSILON.
[toc] | [prev] | [next] | [standalone]
| From | "James R. Kuyper" <jameskuyper@verizon.net> |
|---|---|
| Date | 2016-09-25 13:14 -0400 |
| Message-ID | <a48fe888-76ca-6342-34f3-26952ab98bef@verizon.net> |
| In reply to | #94035 |
On 09/25/2016 12:39 PM, David Brown wrote:
> On 25/09/16 17:48, James R. Kuyper wrote:
...
>> Here's the original code that I was talking about, in order of execution:
>>
>> main:
>> ... test3();
>>
>> test3:
>> void *p = malloc(sizeof (T1) + sizeof (T2));
>> /* p now points at a buffer; for convenience I'll refer to that buffer
>> using 'p' even in contexts where 'p' is not in scope.
>> */
>> ... blah3(p,p);
>>
>> blah3:
>> T1 blah3(void *p1, void *p2)
>> {
>> /* p1 and p2 are both set equal to p */
>> t1p = p1;
>> t2p = p2;
>> /* t1p and t2p both point at the same location as p */
>> *t1p = T1VALUE; // Write as T1
>> /* The sizeof(T1) bytes starting at p now contain a representation of
>> T1VALUE as an object of type T1, which is now the effective type of
>> that memory.
>> */
>> *t2p = T2VALUE; // Write as T2
>> /* The sizeof(T2) bytes starting at p now contain a representation of
>> T2VALUE as an object of type T2, which is now the effective type of
>> that memory.
>> */
>> temp = *t2p; // Read as T2
>> /* Since *t2p has the type T2, which matches the effective type of that
>> memory, there is no problem reading the value T2VALUE from that
>> memory, which is then stored in temp.
>> */
>
> OK so far...
>
>> t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
>> /* I missed this point: conversion from T2* to T1* is allowed, since
>> this particular pointer is guaranteed to be correctly aligned for
>> either type. However, technically, the standard says nothing about
>> where t1p2 actually points. In principle, the only thing that is
>> guaranteed about the value of t1p2 is that if you convert it back to
>> T2*; the result will compare equal to t2p. For instance, the forward
>> conversion could add 1024 bytes to the position, so long as the reverse
>> conversion subtracted the same amount.
>> In practice, on virtually every real world implementation of C, t1p2
>> will point at the same location as all of the other object pointers in
>> this program, and I believe it was the committee's intent that this be
>> true. However, I haven't managed to convince anyone in authority that
>> there's any need to change the wording to reflect that intent.
>> */
>
> gcc appears to be optimising on the basis that the only defined
> behaviour for t1p2 is that you can covert it back to a T2* and get the
> same pointer as t2p. The assembly it generates is (with my comments):
>
> blah3:
> movq $1, (%rdi) // Store 1 in *t1p
> movl $1, %eax // The return value 1
> movq $2, (%rsi) // Store 2 in *t2p
> ret
>
> test3:
> movl $1, %eax
> ret
I doubt that the t1p2 conversion is the justification used by gcc for
generating this code. That's a purely pedantic issue that bothers only
me - it's not something real implementations handle in any fashion
different from the committee's intent.
I've long assumed that the purpose of the anti-aliasing rules was to
gave implementations considerable freedom to reorder code using pointers
to different types, if the code consisted of a read from one type and a
write to a different type, if that pair of types was not connected by
one of the rules listed in 6.5p7.
However, after analyzing the code above, I realized that the
implementation's freedom is seriously restricted by the possibility that
the pointers point at dynamically allocated memory, due to the fact that
the effective type can change with each write. In fact, I'm wondering if
the anti-aliasing rules give implementations any freedom at all to
reorder such code - could I be misunderstanding either 6.5p6 and p7?
The optimization you show above would be permitted if the two pointers
didn't point at dynamically allocated memory, and I'm wondering if gcc's
mistake was in failing to consider that possibility.
>> *t1p2 = temp; // Write as T1
>> /* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes
>> starting at p. The effective type of that memory is now T1.
>> */
>> return *t1p; // Read as T1
...
>> T2VALUE is 2. By what argument would anyone claim that a value of 1
>> could be printed out?
>
> It is the result gcc gives.
Not on Ben's machine. Have the two of you resolved which of you is using
the later version of gcc?
> This is either a valid result due to the conversion of pointer types
> mentioned above (and claims about "virtually every real world
> implementation of C" are simply incorrect, because gcc is a pretty major
> exception), or gcc has a bug here.
>
> To be clear, I would be happier if gcc gave 2 here - the same result as
> other compilers on <gcc.godbolt.org>, and the result one would
> reasonably expect. ...
> ... I would prefer if the C standards said that types
> such as "long", "long long", and "int64_t" were all considered
> "compatible" if they are all the same size (and similarly for "int",
> "long", "int32_t"). ...
The C standard currently allows integer types with the same size and
same signedness to use different byte orders, and even different bit
orders (it allows this by the simple expedient of failing to specify
anything relevant about the byte order or bit order). I believe this
freedom is intentional, though I'm not sure if any real-world
implementation takes advantage of this freedom. I would oppose mandating
that they be compatible.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-09-25 13:47 -0700 |
| Message-ID | <5e6c367f-b103-4ac7-a40b-abff0c10e8c7@googlegroups.com> |
| In reply to | #94038 |
On Sunday, September 25, 2016 at 12:14:26 PM UTC-5, James R. Kuyper wrote:
> I've long assumed that the purpose of the anti-aliasing rules was to
> gave implementations considerable freedom to reorder code using pointers
> to different types, if the code consisted of a read from one type and a
> write to a different type, if that pair of types was not connected by
> one of the rules listed in 6.5p7.
Based upon the C89 rationale, I had assumed that the purpose was to allow
compilers to keep variables in registers when accessing pointers of different
types, and where there was no reason why the compiler should expect aliasing.
The authors of the Standard wanted to make it clear that given something like:
int x;
int foo(unsigned *p, unsigned q)
{
x=234;
*p = q;
return x;
}
a compiler couldn't use the fact that "x" was signed and "*p" was unsigned
as justification to keep x in a register across the write to "p", but they
also didn't want to mandate that compilers regard the behavior as defined
if the bit pattern of q (as an unsigned) would be a trap representation for
"int". Especially considering the heavy use of global variables by code of
that era, register-caching those represented easy low-hanging fruit for a
compiler.
> However, after analyzing the code above, I realized that the
> implementation's freedom is seriously restricted by the possibility that
> the pointers point at dynamically allocated memory, due to the fact that
> the effective type can change with each write. In fact, I'm wondering if
> the anti-aliasing rules give implementations any freedom at all to
> reorder such code - could I be misunderstanding either 6.5p6 and p7?
It is not possible to have one set of rules which will be suitable for both
systems programming and high-end computing without adding directives to
control aliasing. The present rules tie the hands of both compilers and
programmers needlessly.
The solution would be to have some distinct recognized aliasing modes,
most of which have precisely-defined requirements for programmers and
implementations, but with the default mode being relatively open-ended.
All implementations would be required to support a mode in which writing
anything of any type will behave as though all the bytes it occupies have
the object's defined representation written to them, and reading anything
of any type will interpret the last values written to the underlying bytes
in the manner defined for that type, and would be required to accept
directives indicating that code can work with other modes [any other mode
could be supported in compliant--though not necessarily performant--fashion
by any compiler simply by having it use the "baseline" mode if it has no
faster mode that complies with the requirements of the mode specified].
Adding aliasing modes would make it possible for compilers to rid themselves
of any need to recognize the possibility that code might repurpose storage
without notifying the compiler. Provided that adequate means existed to
let the compiler know when aliasing must be expected, and code was allowed to
use aliasing once notice was given, even a very aggressive mode could be
suitable for writing new systems-programming code (less aggressive modes
would be needed mainly to handle code which hasn't yet had the appropriate
notifications added to it).
> The optimization you show above would be permitted if the two pointers
> didn't point at dynamically allocated memory, and I'm wondering if gcc's
> mistake was in failing to consider that possibility.
I'm pretty sure that gcc's mistake is in regarding the write to *t1p2 as a
no-op on the basis that the 64 bits being stored are known to match precisely
the 64 bits the storage already contains. I consider the bug quite serious,
however, since it would be entirely reasonable for someone who has to pass
data between different APIs to do something like:
void *p = malloc(100 * sizeof (long long))
get_data_as_longs(p); // void get_data_as_longs(long *p);
for (i=100-1; i>=0; i--) // long long should be at least as large as long
((long long*)p)[i] = ((long*)p)[i];
use_data_as_long_long(p);
In the event that "long" and "long long" have the same representation, it
would be good for a compiler to omit the middle loop, but not for it to
allow whole-program optimization to sequence the reads of "long long" in
the "use" function ahead of the writes of "long" in the "get" function.
I would not consider the above pattern obscure, but given the way gcc works
I wouldn't consider it safe.
> The C standard currently allows integer types with the same size and
> same signedness to use different byte orders, and even different bit
> orders (it allows this by the simple expedient of failing to specify
> anything relevant about the byte order or bit order). I believe this
> freedom is intentional, though I'm not sure if any real-world
> implementation takes advantage of this freedom. I would oppose mandating
> that they be compatible.
If hardware supports two different 64-bit types, it would be reasonable for
a C implementation *on that hardware* to treat "long" and "long long" as
incompatible 64-bit types, and there would be little benefit on such a
platform to treating pointers to those types as alias-compatible.
I would question the judgment, however, of anyone who thinks that on
platforms where both types have *the same documented data format*, the value
of having a compiler's default behavior treat the types as not being alias-
compatible outweighs the difficulties such a design will impose on code that
needs to exchange data between different APIs.
Any benefit that could be achieved by having "long" and "long long" be
distinct types could be achieved, better and more safely, by defining a
#pragma or other directive which would tell the compiler that certain
typedefs should be regarded as incompatible with others even when both
have the same underlying type, and should be alias-compatible with certain
others whether or not they have the same underlying type.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2016-09-28 10:39 -0700 |
| Message-ID | <kfna8erc49c.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #94048 |
supercat@casperkitty.com writes: > On Sunday, September 25, 2016 at 12:14:26 PM UTC-5, James R. Kuyper wrote: >> I've long assumed that the purpose of the anti-aliasing rules was to >> gave implementations considerable freedom to reorder code using pointers >> to different types, if the code consisted of a read from one type and a >> write to a different type, if that pair of types was not connected by >> one of the rules listed in 6.5p7. > > Based upon the C89 rationale, I had assumed that the purpose was to allow > compilers to keep variables in registers when accessing pointers of different > types, [...] Presumably that is one motivation, but it certainly is not the only motivation.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-09-25 23:25 +0200 |
| Message-ID | <ns9fcj$orn$1@dont-email.me> |
| In reply to | #94038 |
On 25/09/16 19:14, James R. Kuyper wrote:
> On 09/25/2016 12:39 PM, David Brown wrote:
>> On 25/09/16 17:48, James R. Kuyper wrote:
> ...
>>> Here's the original code that I was talking about, in order of
>>> execution:
>>>
>>> main:
>>> ... test3();
>>>
>>> test3:
>>> void *p = malloc(sizeof (T1) + sizeof (T2));
>>> /* p now points at a buffer; for convenience I'll refer to that buffer
>>> using 'p' even in contexts where 'p' is not in scope.
>>> */
>>> ... blah3(p,p);
>>>
>>> blah3:
>>> T1 blah3(void *p1, void *p2)
>>> {
>>> /* p1 and p2 are both set equal to p */
>>> t1p = p1;
>>> t2p = p2;
>>> /* t1p and t2p both point at the same location as p */
>>> *t1p = T1VALUE; // Write as T1
>>> /* The sizeof(T1) bytes starting at p now contain a representation of
>>> T1VALUE as an object of type T1, which is now the effective type of
>>> that memory.
>>> */
>>> *t2p = T2VALUE; // Write as T2
>>> /* The sizeof(T2) bytes starting at p now contain a representation of
>>> T2VALUE as an object of type T2, which is now the effective type of
>>> that memory.
>>> */
>>> temp = *t2p; // Read as T2
>>> /* Since *t2p has the type T2, which matches the effective type of that
>>> memory, there is no problem reading the value T2VALUE from that
>>> memory, which is then stored in temp.
>>> */
>>
>> OK so far...
>>
>>> t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
>>> /* I missed this point: conversion from T2* to T1* is allowed, since
>>> this particular pointer is guaranteed to be correctly aligned for
>>> either type. However, technically, the standard says nothing about
>>> where t1p2 actually points. In principle, the only thing that is
>>> guaranteed about the value of t1p2 is that if you convert it back to
>>> T2*; the result will compare equal to t2p. For instance, the forward
>>> conversion could add 1024 bytes to the position, so long as the reverse
>>> conversion subtracted the same amount.
>>> In practice, on virtually every real world implementation of C, t1p2
>>> will point at the same location as all of the other object pointers in
>>> this program, and I believe it was the committee's intent that this be
>>> true. However, I haven't managed to convince anyone in authority that
>>> there's any need to change the wording to reflect that intent.
>>> */
>>
>> gcc appears to be optimising on the basis that the only defined
>> behaviour for t1p2 is that you can covert it back to a T2* and get the
>> same pointer as t2p. The assembly it generates is (with my comments):
>>
>> blah3:
>> movq $1, (%rdi) // Store 1 in *t1p
>> movl $1, %eax // The return value 1
>> movq $2, (%rsi) // Store 2 in *t2p
>> ret
>>
>> test3:
>> movl $1, %eax
>> ret
>
> I doubt that the t1p2 conversion is the justification used by gcc for
> generating this code. That's a purely pedantic issue that bothers only
> me - it's not something real implementations handle in any fashion
> different from the committee's intent.
>
> I've long assumed that the purpose of the anti-aliasing rules was to
> gave implementations considerable freedom to reorder code using pointers
> to different types, if the code consisted of a read from one type and a
> write to a different type, if that pair of types was not connected by
> one of the rules listed in 6.5p7.
> However, after analyzing the code above, I realized that the
> implementation's freedom is seriously restricted by the possibility that
> the pointers point at dynamically allocated memory, due to the fact that
> the effective type can change with each write. In fact, I'm wondering if
> the anti-aliasing rules give implementations any freedom at all to
> reorder such code - could I be misunderstanding either 6.5p6 and p7?
>
> The optimization you show above would be permitted if the two pointers
> didn't point at dynamically allocated memory, and I'm wondering if gcc's
> mistake was in failing to consider that possibility.
I know /I/ failed to consider the effect of dynamically allocated
memory. It is possible that gcc does so too, especially since it has
eliminated the dynamic allocation.
>
>>> *t1p2 = temp; // Write as T1
>>> /* T2VALUE is converted to type T1, and stored in the sizeof(T1) bytes
>>> starting at p. The effective type of that memory is now T1.
>>> */
>>> return *t1p; // Read as T1
>
> ...
>>> T2VALUE is 2. By what argument would anyone claim that a value of 1
>>> could be printed out?
>>
>> It is the result gcc gives.
>
> Not on Ben's machine. Have the two of you resolved which of you is using
> the later version of gcc?
Yes. He had some other flags that affected the compilation.
>
>> This is either a valid result due to the conversion of pointer types
>> mentioned above (and claims about "virtually every real world
>> implementation of C" are simply incorrect, because gcc is a pretty major
>> exception), or gcc has a bug here.
>>
>> To be clear, I would be happier if gcc gave 2 here - the same result as
>> other compilers on <gcc.godbolt.org>, and the result one would
>> reasonably expect. ...
>
>> ... I would prefer if the C standards said that types
>> such as "long", "long long", and "int64_t" were all considered
>> "compatible" if they are all the same size (and similarly for "int",
>> "long", "int32_t"). ...
>
> The C standard currently allows integer types with the same size and
> same signedness to use different byte orders, and even different bit
> orders (it allows this by the simple expedient of failing to specify
> anything relevant about the byte order or bit order). I believe this
> freedom is intentional, though I'm not sure if any real-world
> implementation takes advantage of this freedom. I would oppose mandating
> that they be compatible.
If an implementation had different byte orderings for two equally sized
types, then I would happily agree that pointers should be incompatible.
(I would also be pleased to see such a feature - sometimes in my
programming I need to deal with non-native byte ordering. gcc now has
support for non-native byte ordering in structs, which is nice.)
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-09-25 13:10 -0700 |
| Message-ID | <fe48733e-7d15-4442-9a6e-449ea39b9827@googlegroups.com> |
| In reply to | #94035 |
On Sunday, September 25, 2016 at 11:39:43 AM UTC-5, David Brown wrote: > gcc appears to be optimising on the basis that the only defined > behaviour for t1p2 is that you can covert it back to a T2* and get the > same pointer as t2p. The assembly it generates is (with my comments): Casting the pointer to void* would be required to yield a pointer matching the one passed into the function, and casting that to T1 would be guaranteed to yield a pointer to the same storage. The Standard may not explicitly describe the effect of casting a pointer directly from (T2*) to (T1*), but in cases where a cast from (T2*) to (void*) would be defined, and likewise a cast from the resulting (void*) to (T1*), it would seem curious that the Standard would mandate that compilers accept a direct cast syntactically if it didn't intend that behavior be defined, and I can't think of any resulting pointer value the authors of the Standard would have intended to allow that would differ from that of casting through void*. I can imagine implementations where an explicit cast through (void*) might offer semantic guarantees beyond those which the Standard requires, and which it would not offer on a direct cast from (T2*) to (*T1), but this scenario doesn't involve any such guarantees.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-09-25 12:55 -0700 |
| Message-ID | <cb58001a-2327-4cc4-ae1e-8e6926f1af59@googlegroups.com> |
| In reply to | #94031 |
On Sunday, September 25, 2016 at 10:48:26 AM UTC-5, James R. Kuyper wrote: > At no point does this code do anything which relies upon the assumption > that long long and int64_t are the same underlying type. It would work > equally well if T2 were any integer type other than _Bool. So far as I can tell, the code *would* work if T1 and T2 were anything other than a 64-bit "long" and 64-bit "long long"--I made them typedefs to facilitate testing other types, but the cases where the code works aren't interesting. What's interesting is the case where the code fails. When using direct assignment, the only case I've noticed that fails is when using two 64-bit integer types with the same representation, though if I knew how to configure the x86 ARM to make "long" be 32 bits it might be interesting to try with "int" and "long". If I recall, both "long double" and "double" had the same 64-bit representation, but the compiler generated correct code in that case. I didn't test whether gcc is treating them as distinct types for aliasing purposes, however.
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2016-09-25 20:38 +0100 |
| Message-ID | <87lgyfepnc.fsf@bsb.me.uk> |
| In reply to | #94018 |
David Brown <david.brown@hesbynett.no> writes: > On 24/09/16 22:03, Ben Bacarisse wrote: >> David Brown <david.brown@hesbynett.no> writes: > <snip> >>> But I could be wrong - and if this really is incorrect behaviour from >>> gcc, then it needs reported and fixed. >> >> And *I* could be wrong, but I've gone though all 9 object accesses and >> every one appears to be explicitly permitted by p6 and p7 of section >> 6.5. >> >> <snip> >>>> My gcc (5.2.1 20151010) gives 2 for all -Ox. Presumably you have a >>>> newer version? >>> >>> I am testing here with <https://gcc.godbolt.org/> for convenience. It >>> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on >>> gcc 4.7 onwards. gcc 4.5 and 4.6 give 2. >> >> Including 5.2? My system is 64-bit Linux. (I could not see how to get >> that site to show me the output.) >> >> <snip> >> > > My test on gcc.godbolt.org is here: <big link snipped> My tests were local because I could not see how to get the program to run at gcc.godbolt.org -- presumably that's not permitted. Anyway, it turns out that other compiler options were undoing the effects of -O2 (I turn the sanitizer on by default) so I now see what you see. > The details of the standards here is getting beyond me. I fond that surprising. The relevant parts just say that the effective type of object in allocated storage is set by a write operation, and the code only ever reads an object after a write operation has been done using that same type. It all looks fine to me. > When you and > James both think the answer should be 1, and 2 is not allowed, For my part, it's the other way round. I'm, saying that there is no undefined behaviour regardless of what type int64_t actually is. That means that 1 is not permitted and blah3 must return 2. But (despite your kind words below), I'm not much of a language lawyer. I find the effective type rules to be often baffling. It just seems to me that they are quite clear in this particular case. > then I > am far from confident about 2 being allowable I thought you were saying that anything was allowable in the case where int64_t and long long int were not compatible types? > - you are both more > better at "language lawyering" than me. But I do know that gcc will > do this sort of transformation in practice, and in real code - you > need to be very careful in mixing pointers to different integer types > even when you know they are the same underlying hardware types. Well, yes, we can all now see that gcc will do this! Being very careful may then something of an understatement, since it seems that programmers must not only take care to stick to the C standard, but must also avoid these other issues. > Maybe it's time to pass this on to the gcc mailing lists, and ask how > they interpret it? That would be interesting. It's obviously a long-standing optimisation, but I don't see on what basis it is being done. -- Ben.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-09-25 23:20 +0200 |
| Message-ID | <ns9f32$o08$1@dont-email.me> |
| In reply to | #94042 |
On 25/09/16 21:38, Ben Bacarisse wrote: > David Brown <david.brown@hesbynett.no> writes: > >> On 24/09/16 22:03, Ben Bacarisse wrote: >>> David Brown <david.brown@hesbynett.no> writes: >> <snip> >>>> But I could be wrong - and if this really is incorrect behaviour from >>>> gcc, then it needs reported and fixed. >>> >>> And *I* could be wrong, but I've gone though all 9 object accesses and >>> every one appears to be explicitly permitted by p6 and p7 of section >>> 6.5. >>> >>> <snip> >>>>> My gcc (5.2.1 20151010) gives 2 for all -Ox. Presumably you have a >>>>> newer version? >>>> >>>> I am testing here with <https://gcc.godbolt.org/> for convenience. It >>>> is targeting 64-bit Linux, and the result is 1 for -O2 and above, on >>>> gcc 4.7 onwards. gcc 4.5 and 4.6 give 2. >>> >>> Including 5.2? My system is 64-bit Linux. (I could not see how to get >>> that site to show me the output.) >>> >>> <snip> >>> >> >> My test on gcc.godbolt.org is here: > > <big link snipped> > > My tests were local because I could not see how to get the program to > run at gcc.godbolt.org -- presumably that's not permitted. > I was not actually running the code - merely compiling it and looking at the generated assembly. I am not an expert at x86 assembly, but I can read it well enough to see the value being returned by the functions and the value being printed out by main (especially when I change the constants to 100 and 200 rather than 1 and 2). gcc.godbolt.org makes it easy to test a variety of compilers - more than I have installed locally. > Anyway, it turns out that other compiler options were undoing the > effects of -O2 (I turn the sanitizer on by default) so I now see what > you see. OK, that explains it. > >> The details of the standards here is getting beyond me. > > I fond that surprising. The relevant parts just say that the effective > type of object in allocated storage is set by a write operation, and the > code only ever reads an object after a write operation has been done > using that same type. It all looks fine to me. > To be more accurate, I mean we are touching on an area where I am not entirely confident, and I think it is quite likely that I am missing something subtle. I hadn't thought about the difference made by the buffers being dynamically allocated, for example. >> When you and >> James both think the answer should be 1, and 2 is not allowed, > > For my part, it's the other way round. Yes, I am sorry I got that mixed up! (See my post to James.) > I'm, saying that there is no > undefined behaviour regardless of what type int64_t actually is. That > means that 1 is not permitted and blah3 must return 2. But (despite > your kind words below), I'm not much of a language lawyer. I find the > effective type rules to be often baffling. It just seems to me that > they are quite clear in this particular case. > >> then I >> am far from confident about 2 being allowable Please pretend I wrote "1" there. > > I thought you were saying that anything was allowable in the case where > int64_t and long long int were not compatible types? That is what I thought, yes. But when you and James think otherwise, I can't be confident any more. > >> - you are both more >> better at "language lawyering" than me. But I do know that gcc will >> do this sort of transformation in practice, and in real code - you >> need to be very careful in mixing pointers to different integer types >> even when you know they are the same underlying hardware types. > > Well, yes, we can all now see that gcc will do this! Being very careful > may then something of an understatement, since it seems that programmers > must not only take care to stick to the C standard, but must also avoid > these other issues. > >> Maybe it's time to pass this on to the gcc mailing lists, and ask how >> they interpret it? > > That would be interesting. It's obviously a long-standing optimisation, > but I don't see on what basis it is being done. > I'll ask, and report back.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2016-09-28 07:15 -0700 |
| Message-ID | <kfnvaxgaz66.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #94042 |
Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > David Brown <david.brown@hesbynett.no> writes: > [discussing a particular case of gcc behavior w.r.t. effective > type rules] > >> Maybe it's time to pass this on to the gcc mailing lists, and ask >> how they interpret it? > > That would be interesting. It's obviously a long-standing > optimisation, but I don't see on what basis it is being done. I am hoping not to be involved in this discussion too deeply, but would like to make a few remarks. I agree with your conclusion that the example code conforms to the letter of the Standard. AFAICT that code satisfies the requirements of effective type rules (but let me emphasize, as I read what the words say, which may not be the same as what is meant). I too would like to see this case (perhaps with simpler code) submitted as a gcc bug report (and maybe also mailing lists, but IMO an official response is important). A response to a bug report might be either "yes this is a bug and we will fix it", or might be "this isn't a bug because what the Standard means is X". The second possibility occurring would not surprise me greatly. IMO this example also deserves filing a Defect Report. I call it a defect because either the Standard doesn't mean what it says, which is obviously a defect, or it produces a conclusion that is highly surprising and probably not what some implementors expect. Either way, a clarification is warranted. I wouldn't be surprised if an official committee response to a Defect Report reached a different conclusion about whether the behavior in the example code is undefined behavior. I'm sure many people remember the earlier discussions, before C11 was done, about the phrase "may be read only to determine the value to be stored" (or something like that). We now know that the "literal meaning" of that phrase is not what was intended. A similar situation may apply in this case. At the end of the day the only thing that matters is what WG14 intended, and the only way to be sure here is to ask them.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-09-28 21:29 +0200 |
| Message-ID | <nsh5lu$il5$1@dont-email.me> |
| In reply to | #94186 |
On 28/09/16 16:15, Tim Rentsch wrote: > Ben Bacarisse <ben.usenet@bsb.me.uk> writes: > >> David Brown <david.brown@hesbynett.no> writes: >> [discussing a particular case of gcc behavior w.r.t. effective >> type rules] >> >>> Maybe it's time to pass this on to the gcc mailing lists, and ask >>> how they interpret it? >> >> That would be interesting. It's obviously a long-standing >> optimisation, but I don't see on what basis it is being done. I posted to the gcc help mailing list. I hope people here can have a look at the answers from the gcc community and developers, and consider the matter. Maybe a defect report is the right way to go, or perhaps others (such as you, Tim) would like to add to the gcc thread. The mailing list is on gmane as gmane.comp.gcc.help for those that prefer a Usenet interface to a mailing list. You can also post to gcc-help@gcc.gnu.org without joining the list (the traffic is not too high). <https://gcc.gnu.org/ml/gcc-help/2016-09/msg00087.html> > > I am hoping not to be involved in this discussion too deeply, but > would like to make a few remarks. > > I agree with your conclusion that the example code conforms to > the letter of the Standard. AFAICT that code satisfies the > requirements of effective type rules (but let me emphasize, > as I read what the words say, which may not be the same as > what is meant). > > I too would like to see this case (perhaps with simpler code) > submitted as a gcc bug report (and maybe also mailing lists, > but IMO an official response is important). > > A response to a bug report might be either "yes this is a bug and > we will fix it", or might be "this isn't a bug because what the > Standard means is X". The second possibility occurring would > not surprise me greatly. > > IMO this example also deserves filing a Defect Report. I call it > a defect because either the Standard doesn't mean what it says, > which is obviously a defect, or it produces a conclusion that > is highly surprising and probably not what some implementors > expect. Either way, a clarification is warranted. > > I wouldn't be surprised if an official committee response to a > Defect Report reached a different conclusion about whether the > behavior in the example code is undefined behavior. I'm sure > many people remember the earlier discussions, before C11 was > done, about the phrase "may be read only to determine the value > to be stored" (or something like that). We now know that the > "literal meaning" of that phrase is not what was intended. A > similar situation may apply in this case. At the end of the > day the only thing that matters is what WG14 intended, and > the only way to be sure here is to ask them. >
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-09-24 10:52 -0700 |
| Message-ID | <b04f3d50-36d9-4f06-9880-7690ed99d19a@googlegroups.com> |
| In reply to | #93980 |
On Saturday, September 24, 2016 at 9:56:08 AM UTC-5, Ben Bacarisse wrote: > My gcc (5.2.1 20151010) gives 2 for all -Ox. Presumably you have a > newer version? The code is for x86-64 (as found on godbolt.org), where both "long" and "long long" are 64 bits. If the two types have different representations, then reading a value of one type and writing it as the other will be recognized as having an effect. I think that what is happening is that gcc's code generation is being inconsistent with regard to whether the two 64-bit types should be considered interchangeable. If the types are interchangeable, then the act of reading storage as T2 and writing the same storage as T1 may be omitted entirely, but the earlier write as T2 would need to be visible to the subsequent read as T1. If the types are not interchange-able, then the read and write need not generate any actual machine code, but must behave as a read of type T2 followed by a write of T1.
[toc] | [prev] | [next] | [standalone]
| From | supercat@casperkitty.com |
|---|---|
| Date | 2016-09-24 10:33 -0700 |
| Message-ID | <42564e5d-31d4-4686-b994-7d58e6ddeaba@googlegroups.com> |
| In reply to | #93977 |
On Saturday, September 24, 2016 at 9:29:38 AM UTC-5, David Brown wrote:
> If T1 and T2 are compatible types (as might be the case, such as on
> Windows), then the answer will be 2. If they are incompatible types,
> such as on 64-bit Linux, the answer is undefined - you are trying to
> access the same object through pointers to two incompatible types.
No, I am not. The rules allow storage with no declared type to be written
as any type, and the write sets the Effective Type until the storage is
written again. The code I posted always reads the storage as the last type
written (i.e. its Effective Type).
While one could argue that the Effective Type T2 remains effective because
the bit patterns written to storage will match what's already there, and
the second write consequently doesn't "modify the value", such a reading
would directly contradict the definition of "modify" in 3.2 (and would
also contradict the language which says that storing a value of type T1
would set the Effective Type to T1).
> Some
> compiler and optimisation options will give 2, others will give 1,
> others could, in theory, give something else - but I think that's
> unlikely in practice.
The code does not invoke UB.
> gcc gives 1 with optimisation -O2 and above, on 64-bit Linux. There is
> no bug here in gcc as far as I can see - your code is incorrect.
It tests whether reading an object via T2*, converting the value to T1,
and writing the converted value via T1* is properly recognized as setting
the Effective Type of the object to type T1.
> > Since you wanted me to dig it up, here's the example I posted before.
> >
> > https://godbolt.org/g/75oLGx
>
> Maybe the link is not working as expected - it appeared to have the code:
>
> // Type your code here, or load an example.
> int square(int num) {
> return num * num;
> }
I don't think the "short link" function on godbolt is supposed to require
cookies, so I'm not sure why the link would simply show the default example
program on your machine. I posted the source text above, however, and will
paste it below for convenience:
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
typedef long long T1;
typedef int64_t T2;
#define T1FMT "%lld"
#define T1VALUE 1
#define T2VALUE 2
T1 blah3(void *p1, void *p2)
{
T1 *t1p, *t1p2;
T2 *t2p;
T1 temp;
t1p = p1;
t2p = p2;
*t1p = T1VALUE; // Write as T1
*t2p = T2VALUE; // Write as T2
temp = *t2p; // Read as T2
t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
*t1p2 = temp; // Write as T1
return *t1p; // Read as T1
}
T1 test3(void)
{
void *p = malloc(sizeof (T1) + sizeof (T2));
T1 result = blah3(p,p);
free(p);
return result;
}
int main(void)
{
T1 result = test3();
printf("The result is " T1FMT, result);
return 0;
}
> I don't see how this relates to your point.
The default demo program for godbolt has nothing to do with my point; I have
no idea why it would show up on your end.
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2016-09-25 12:46 +0200 |
| Message-ID | <ns89tu$lj2$2@dont-email.me> |
| In reply to | #93984 |
On 24/09/16 19:33, supercat@casperkitty.com wrote:
> On Saturday, September 24, 2016 at 9:29:38 AM UTC-5, David Brown wrote:
>>> Since you wanted me to dig it up, here's the example I posted before.
>>>
>>> https://godbolt.org/g/75oLGx
>>
>> Maybe the link is not working as expected - it appeared to have the code:
>>
>> // Type your code here, or load an example.
>> int square(int num) {
>> return num * num;
>> }
>
> I don't think the "short link" function on godbolt is supposed to require
> cookies, so I'm not sure why the link would simply show the default example
> program on your machine. I posted the source text above, however, and will
> paste it below for convenience:
>
>> I don't see how this relates to your point.
>
> The default demo program for godbolt has nothing to do with my point; I have
> no idea why it would show up on your end.
>
OK. I thought you were giving a link to a different example. Maybe the
short links don't work, or maybe the problem is on my browser. When I
posted a link in a different post, I tried a full link to see if that
works better.
Sorry for the confusion here.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2016-09-24 13:58 -0700 |
| Message-ID | <lnfuopuia5.fsf@kst-u.example.com> |
| In reply to | #93948 |
supercat@casperkitty.com writes:
> On Friday, September 23, 2016 at 2:49:43 AM UTC-5, David Brown wrote:
>> On 22/09/16 18:52, supercat wrote:
>> Your first claim was that gcc (6.2) incorrectly handles code in a way
>> that goes against the unambiguous rules of the standards. This is a
>> serious allegation, and should be backed up with concrete examples and
>> bug reports. The gcc team take all "incorrect code generation" bugs
>> extremely seriously. And while /you/ might not use gcc, millions of
>> others do use it. Someone here (such as me) will happily file a bug
>> report if you have a specific bug.
>>
>> But now you have modified back to your usual "gcc optimises too well -
>> it follows the requirements of the real C standards, rather than my
>> imaginary specifications of thirty years ago".
>>
>> So which is it? Can you give us a concrete example of buggy code, that
>> we can paste into <http://gcc.godbolt.org/#> and compare results with
>> different gcc versions and different compilers? You can't just refer to
>> "I've posted about it before" - you have posted hundreds or thousands of
>> snippets in this group.
>
> #include <stdint.h>
> #include <string.h>
> #include <stdlib.h>
> #include <stdio.h>
>
> typedef long long T1;
> typedef int64_t T2;
> #define T1FMT "%lld"
> #define T1VALUE 1
> #define T2VALUE 2
>
> T1 blah3(void *p1, void *p2)
> {
> T1 *t1p, *t1p2;
> T2 *t2p;
> T1 temp;
>
> t1p = p1;
> t2p = p2;
> *t1p = T1VALUE; // Write as T1
> *t2p = T2VALUE; // Write as T2
> temp = *t2p; // Read as T2
> t1p2 = (T1*)t2p; // Visible T2 to T1 pointer conversion
> *t1p2 = temp; // Write as T1
> return *t1p; // Read as T1
> }
>
> T1 test3(void)
> {
> void *p = malloc(sizeof (T1) + sizeof (T2));
> T1 result = blah3(p,p);
> free(p);
> return result;
> }
> int main(void)
> {
> T1 result = test3();
> printf("The result is " T1FMT, result);
> return 0;
> }
[...]
> So there's a sample of buggy code. Similar thing can happen if there are
> two structure types that have the same representation.
I found that the typedefs and macros made the code difficult to read;
YMMV.
Here's my version, which I believe is equivalent -- assuming
that long and long long have the same size and representation,
and that int64_t is a typedef for long. (I also added a newline
to the output.)
On my x86_64 system, using gcc 6.2.0, I get "The result is 2"
with -O0 and -O1, and "The result is 1" with -O2 and -O3.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
long long func1(void *p1, void *p2) {
long long *llp1 = p1;
long *lp = p2;
*llp1 = 1; // Write as long long
*lp = 2; // Write as long
long long temp = *lp; // Read as long
long long *llp2 = (long long*)lp; // Visible long to long long
pointer conversion
*llp2 = temp; // Write as long long
return *llp1; // Read as long long
}
long long func2(void) {
void *p = malloc(sizeof (long long) + sizeof (long));
long long result = func1(p,p);
free(p);
return result;
}
int main(void) {
assert(sizeof (long) == sizeof (long long));
printf("The result is %lld\n", func2());
}
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[toc] | [prev] | [next] | [standalone]
Page 3 of 5 — ← Prev page 1 2 [3] 4 5 Next page →
Back to top | Article view | comp.lang.c
csiph-web