Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #73265 > unrolled thread

Pointers as error values

Started by"Morten W. Petersen" <morphex@gmail.com>
First post2015-10-19 00:53 -0700
Last post2015-10-22 06:06 +0000
Articles 20 on this page of 80 — 23 participants

Back to article view | Back to comp.lang.c


Contents

  Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-19 00:53 -0700
    Re: Pointers as error values gazelle@shell.xmission.com (Kenny McCormack) - 2015-10-19 08:26 +0000
      Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-19 02:27 -0700
      Re: Pointers as error values Richard Damon <Richard@Damon-Family.org> - 2015-10-19 23:38 -0400
    Re: Pointers as error values jacobnavia <jacob@jacob.remcomp.fr> - 2015-10-19 10:34 +0200
      Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-19 02:29 -0700
      Re: Pointers as error values mark.bluemel@gmail.com - 2015-10-19 05:53 -0700
    Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-19 10:00 +0000
    Re: Pointers as error values Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-10-19 14:00 +0000
    Re: Pointers as error values gwowen <gwowen@gmail.com> - 2015-10-19 08:02 -0700
      Re: Pointers as error values James Kuyper <jameskuyper@verizon.net> - 2015-10-19 11:53 -0400
    Re: Pointers as error values Ken Brody <kenbrody@spamcop.net> - 2015-10-19 11:25 -0400
    Re: Pointers as error values supercat@casperkitty.com - 2015-10-19 08:41 -0700
    Re: Pointers as error values Keith Thompson <kst-u@mib.org> - 2015-10-19 08:59 -0700
      Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-21 07:32 +0200
        Re: Pointers as error values Ian Collins <ian-news@hotmail.com> - 2015-10-21 19:17 +1300
          Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-21 08:31 +0200
        Re: Pointers as error values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-21 12:46 +0100
        Re: Pointers as error values Robert Wessel <robertwessel2@yahoo.com> - 2015-10-21 09:35 -0500
          Re: Pointers as error values Ken Brody <kenbrody@spamcop.net> - 2015-10-21 15:24 -0400
            Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-22 05:44 +0000
        Re: Pointers as error values Keith Thompson <kst-u@mib.org> - 2015-10-21 10:41 -0700
          Re: Pointers as error values supercat@casperkitty.com - 2015-10-21 11:28 -0700
        Re: Pointers as error values John Temples <usenet@xargs-spam.com> - 2015-10-21 17:45 +0000
          Re: Pointers as error values James Kuyper <jameskuyper@verizon.net> - 2015-10-21 14:15 -0400
            Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-29 16:59 +0100
              Re: Pointers as error values supercat@casperkitty.com - 2015-10-29 12:35 -0700
                Re: Pointers as error values raltbos@xs4all.nl (Richard Bos) - 2015-10-29 21:45 +0000
                  Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-30 06:09 +0100
                    Re: Pointers as error values Rosario19 <Ros@invalid.invalid> - 2015-10-30 08:59 +0100
                      Re: Pointers as error values Rosario19 <Ros@invalid.invalid> - 2015-10-30 09:07 +0100
                      Re: Pointers as error values Rosario19 <Ros@invalid.invalid> - 2015-10-30 09:38 +0100
                        Re: Pointers as error values Rosario19 <Ros@invalid.invalid> - 2015-10-30 09:40 +0100
                    Re: Pointers as error values Robert Wessel <robertwessel2@yahoo.com> - 2015-10-30 04:56 -0500
                    Re: Pointers as error values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-30 11:00 +0000
              Re: Pointers as error values Robert Wessel <robertwessel2@yahoo.com> - 2015-10-29 23:48 -0500
                Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-30 11:05 +0100
                  Re: Pointers as error values Richard Damon <Richard@Damon-Family.org> - 2015-10-30 07:45 -0400
                    Re: Pointers as error values Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-10-30 05:04 -0700
                      Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-30 16:09 +0100
                        Re: Pointers as error values Keith Thompson <kst-u@mib.org> - 2015-10-30 11:16 -0700
                          Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-30 20:58 +0000
                            Re: Pointers as error values Eric Sosman <esosman@comcast-dot-net.invalid> - 2015-10-30 17:12 -0400
                            Re: Pointers as error values supercat@casperkitty.com - 2015-10-30 14:54 -0700
                            Re: Pointers as error values Robert Wessel <robertwessel2@yahoo.com> - 2015-10-30 18:48 -0500
                              Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-11-01 04:00 +0000
                                Re: Pointers as error values Robert Wessel <robertwessel2@yahoo.com> - 2015-11-01 01:24 -0500
                          Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-31 20:35 +0100
                            Re: Pointers as error values supercat@casperkitty.com - 2015-10-31 13:33 -0700
                        Re: Pointers as error values Richard Damon <Richard@Damon-Family.org> - 2015-10-30 22:19 -0400
                    Re: Pointers as error values supercat@casperkitty.com - 2015-10-30 08:22 -0700
                  Re: Pointers as error values Geoff <geoff@invalid.invalid> - 2015-10-30 13:11 -0700
                    Re: Pointers as error values Geoff <geoff@invalid.invalid> - 2015-10-30 13:23 -0700
        Re: Pointers as error values Geoff <geoff@invalid.invalid> - 2015-10-21 11:13 -0700
          Re: Pointers as error values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-21 20:31 +0100
            Re: Pointers as error values Geoff <geoff@invalid.invalid> - 2015-10-22 07:13 -0700
          Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-26 07:16 +0100
            Re: Pointers as error values Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-10-26 09:37 +0000
        Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-22 05:38 +0000
          Re: Pointers as error values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-22 13:51 +0100
          Re: Pointers as error values Keith Thompson <kst-u@mib.org> - 2015-10-22 08:29 -0700
            Re: Pointers as error values supercat@casperkitty.com - 2015-10-22 09:21 -0700
              Re: Pointers as error values Keith Thompson <kst-u@mib.org> - 2015-10-22 10:52 -0700
                Re: Pointers as error values "Morten W. Petersen" <morphex@gmail.com> - 2015-10-26 07:20 +0100
                  Re: Pointers as error values Keith Thompson <kst-u@mib.org> - 2015-10-26 08:09 -0700
                    Re: Pointers as error values supercat@casperkitty.com - 2015-10-26 08:40 -0700
                    Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-26 20:02 +0000
                      Re: Pointers as error values supercat@casperkitty.com - 2015-10-26 13:56 -0700
            Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-22 21:58 +0000
              Re: Pointers as error values James Kuyper <jameskuyper@verizon.net> - 2015-10-22 19:12 -0400
              Re: Pointers as error values asetofsymbols@gmail.com - 2015-10-22 18:36 -0700
                Re: Pointers as error values asetofsymbols@gmail.com - 2015-10-29 12:47 -0700
    Re: Pointers as error values Lőrinczy Zsigmond <nospam@for.me> - 2015-10-20 17:06 +0200
      Re: Pointers as error values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-10-20 19:45 +0100
        Re: Pointers as error values supercat@casperkitty.com - 2015-10-20 14:19 -0700
          Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-21 05:28 +0000
            Re: Pointers as error values supercat@casperkitty.com - 2015-10-21 05:48 -0700
              Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-22 05:52 +0000
            Re: Pointers as error values Ken Brody <kenbrody@spamcop.net> - 2015-10-21 15:19 -0400
              Re: Pointers as error values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2015-10-22 06:06 +0000

Page 3 of 4 — ← Prev page 1 2 [3] 4  Next page →


#74352

FromKeith Thompson <kst-u@mib.org>
Date2015-10-30 11:16 -0700
Message-ID<lneggc9q7w.fsf@kst-u.example.com>
In reply to#74310
"Morten W. Petersen" <morphex@gmail.com> writes:
> On 30.10.2015 13:04, Malcolm McLean wrote:
>> On Friday, October 30, 2015 at 11:45:34 AM UTC, Richard Damon wrote:
>>> On 10/30/15 6:05 AM, Morten W. Petersen wrote:
>>> The issue is that the standard only allows the use of relational
>>> comparisons (like < ) between pointers that are part of the same object
>>> (like an array).
>>>
>>> The practical effect of this is that there are some
>>> machines/implementations where you can get false positives, the most
>>> notable case is for a machine with segmented pointers where < may only
>>> check the offset, and not for the segments to match.
>>>
>> it's a nuisance, because you can't test if ptr is in array a without
>> iterating through a testing every value for equality.  A function
>> ptr_in_range(void *ptr, void *start, void *end) would be handy.
>
> Well, such a function would abstract away the logic so that a define,
> maybe set by some automated test, would choose the right approach.
>
> I've read a bit, and found that a pointer has at least an address
> and a type, in the parsing/compilation part.  It could also contain
> other bits..

A pointer object contains an address at run time.  It also has a type
associated with it, but that information doesn't exist at run time, only
at compile time.  It restricts the things you're allowed to attempt to
do with it.  For example, if you try assign an int* value to a float*
object, the compiler will prevent you from doing so.  If you override
that compile-time check, for example by using a cast, there is
(probably) no run-time check.

> It also looks like x86 and ARM have a flat memory model, which means
> that the pointer in most cases is a simple non-negative number.
>
> So maybe have a compile-time test that checks the architecture and
> makes #define statements based on that?

Yes, you could have a set of #defines, and write one set of code that
works only on systems that satisfy certain characteristics, and another
set of code that works everywhere.

Or you could drop the #defines and just write the second set of code.

If you need to have a whole heck of a lot of distinct invalid non-null
pointer values, then the first approach could make sense.  On systems
where relational operators on pointers to distinct objects yield
consistent results, you could save some execution time.

But I'm having difficulty imagining a realistic scenario where you'd
actually need such a thing.

For example, C's <signal.h> defines just three distinct pointer values
that are not necessarily pointers to actual functions: SIG_DFL, SIG_ERR,
and SIG_IGN (and one of those could be a null pointer).  It doesn't
provide a single operation equivalent to

    (p == SIG_DFL || p == SIG_ERR || p == SIG_IGN)

probably because (a) it's easy enough to write it yourself if you need
it and (b) you probably don't need it.

Do you *really* need a large number of distinct non-null pointer values?
Until you've determined that the answer to that is yes, I suggest not
worrying about how to implement them.

-- 
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]


#74366

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2015-10-30 20:58 +0000
Message-ID<n10lma$6l0$1@speranza.aioe.org>
In reply to#74352
Keith Thompson <kst-u@mib.org> wrote:
> "Morten W. Petersen" <morphex@gmail.com> writes:

(snip)

>> Well, such a function would abstract away the logic so that a define,
>> maybe set by some automated test, would choose the right approach.

>> I've read a bit, and found that a pointer has at least an address
>> and a type, in the parsing/compilation part.  It could also contain
>> other bits..
 
> A pointer object contains an address at run time.  It also has a type
> associated with it, but that information doesn't exist at run time, only
> at compile time.  It restricts the things you're allowed to attempt to
> do with it.  For example, if you try assign an int* value to a float*
> object, the compiler will prevent you from doing so.  If you override
> that compile-time check, for example by using a cast, there is
> (probably) no run-time check.

For comparison purposes, Java and JVM refernces have a type.
You can assign an object reference to a reference variable of the
same class, or a superclass of that class. The ultimate superclass,
Object, works similar to C's (void*).

For assignments to a subclass, you need a cast, and the class will
be tested at run time, with ClassCastException if it fails.

Java also has the instanceof operator such that one can test a
reference before using it.

In the usual C implementation, pointers are just addresses, but
I believe the standard allows for other implementations.
In years past, there has been hardware with extra bits to store
the type of data stored in a location.

>> It also looks like x86 and ARM have a flat memory model, which means
>> that the pointer in most cases is a simple non-negative number.

Large model x86, common in the 16 bit days, rare in the 32 bit days,
has a segmented model. I know of a C compiler that will generate
large model x86 code, but no OS to run it on.

>> So maybe have a compile-time test that checks the architecture and
>> makes #define statements based on that?
 
> Yes, you could have a set of #defines, and write one set of code that
> works only on systems that satisfy certain characteristics, and another
> set of code that works everywhere.

(snip)

-- glen

[toc] | [prev] | [next] | [standalone]


#74368

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2015-10-30 17:12 -0400
Message-ID<n10mbo$70f$1@dont-email.me>
In reply to#74366
On 10/30/2015 4:58 PM, glen herrmannsfeldt wrote:
> [...]
> In the usual C implementation, pointers are just addresses, but
> I believe the standard allows for other implementations.

     Good thing, too.

	http://www.theregister.co.uk/2015/10/28/oracle_sparc_m7/

See those extra four bits?  They mean that every address has sixteen
aliases (only one of which works at any moment).  Also, since different
memory regions may have different extra-bit settings, careless pointer
comparisons (or careless use of pointer<=>integer conversion) may well
misbehave.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#74372

Fromsupercat@casperkitty.com
Date2015-10-30 14:54 -0700
Message-ID<4773e629-a19f-48db-9a94-faea6ddb3ebe@googlegroups.com>
In reply to#74366
On Friday, October 30, 2015 at 3:59:07 PM UTC-5, glen herrmannsfeldt wrote:
> For comparison purposes, Java and JVM refernces have a type.
> You can assign an object reference to a reference variable of the
> same class, or a superclass of that class. The ultimate superclass,
> Object, works similar to C's (void*).

Somewhat more interestingly, for every type Dog in Java there are IIRC 255
array types Dog[], Dog[][], Dog[][][], etc. and Java will allow a reference
to an array of a derived type (e.g. a Beagle[]) to be stored into a variable
of a base-class-array type (e.g. a Dog[]).  A consequence of this is that
an attempt to store an instance of Dog into a Dog[] might fail at runtime,
but it makes it possible to have things like sort routines which can work
on arrays of derived type just as well as on arrays of base type (if a
routine which is designed to sort a Dog[] is given a Beagle[] and shuffles
around elements within that, it will end up reading a reference to what it
thinks is a Dog (but is actually a Beagle) into a variable of type Dog,
and then store that reference into what it thinks is a Dog[] (but is actually
a Beagle[]).

Unfortunately, C doesn't make it possible to write a readable strictly-
conforming program operate on that principle; while the representation of
the leading portion of a DOG and a BEAGLE would match, and while the
representations of DOG* and BEAGLE* would be match, passing the address of
a (BEAGLE*)[] to code expecting a DOG** and having that code read out an
element of type BEAGLE* would invoke Undefined Behavior.

[toc] | [prev] | [next] | [standalone]


#74382

FromRobert Wessel <robertwessel2@yahoo.com>
Date2015-10-30 18:48 -0500
Message-ID<m8083b51nk14lm9qcqvo91ocmp03idsamp@4ax.com>
In reply to#74366
On Fri, 30 Oct 2015 20:58:51 +0000 (UTC), glen herrmannsfeldt
<gah@ugcs.caltech.edu> wrote:

>Keith Thompson <kst-u@mib.org> wrote:
>> "Morten W. Petersen" <morphex@gmail.com> writes:
>
>(snip)
>
>>> Well, such a function would abstract away the logic so that a define,
>>> maybe set by some automated test, would choose the right approach.
>
>>> I've read a bit, and found that a pointer has at least an address
>>> and a type, in the parsing/compilation part.  It could also contain
>>> other bits..
> 
>> A pointer object contains an address at run time.  It also has a type
>> associated with it, but that information doesn't exist at run time, only
>> at compile time.  It restricts the things you're allowed to attempt to
>> do with it.  For example, if you try assign an int* value to a float*
>> object, the compiler will prevent you from doing so.  If you override
>> that compile-time check, for example by using a cast, there is
>> (probably) no run-time check.
>
>For comparison purposes, Java and JVM refernces have a type.
>You can assign an object reference to a reference variable of the
>same class, or a superclass of that class. The ultimate superclass,
>Object, works similar to C's (void*).
>
>For assignments to a subclass, you need a cast, and the class will
>be tested at run time, with ClassCastException if it fails.
>
>Java also has the instanceof operator such that one can test a
>reference before using it.
>
>In the usual C implementation, pointers are just addresses, but
>I believe the standard allows for other implementations.
>In years past, there has been hardware with extra bits to store
>the type of data stored in a location.
>
>>> It also looks like x86 and ARM have a flat memory model, which means
>>> that the pointer in most cases is a simple non-negative number.
>
>Large model x86, common in the 16 bit days, rare in the 32 bit days,
>has a segmented model. I know of a C compiler that will generate
>large model x86 code, but no OS to run it on.


Any 32-bit version of Windows?  All of which support DOS and Win16
applications (including Win10).

IBM mainframe Metal C supports far pointers as well, but in that case
it's used to specify access to other address spaces via the Access
Register mechanism.

[toc] | [prev] | [next] | [standalone]


#74517

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2015-11-01 04:00 +0000
Message-ID<n142o9$rt5$1@speranza.aioe.org>
In reply to#74382
Robert Wessel <robertwessel2@yahoo.com> wrote:

(snip, I wrote)
>>Large model x86, common in the 16 bit days, rare in the 32 bit days,
>>has a segmented model. I know of a C compiler that will generate
>>large model x86 code, but no OS to run it on.
 
> Any 32-bit version of Windows?  All of which support DOS and Win16
> applications (including Win10).

Watcom C supports 48 bit pointers, with a 16 bit segment selector
and 32 bit offset.  It might be that some versions of OS/2 will
do that, but as far as I know not Windows or Linux.  That is, large
model 32 bit.

-- glen

[toc] | [prev] | [next] | [standalone]


#74520

FromRobert Wessel <robertwessel2@yahoo.com>
Date2015-11-01 01:24 -0500
Message-ID<6ubb3bp575tr6hng3qoqkrv5rbe68ulasn@4ax.com>
In reply to#74517
On Sun, 1 Nov 2015 04:00:09 +0000 (UTC), glen herrmannsfeldt
<gah@ugcs.caltech.edu> wrote:

>Robert Wessel <robertwessel2@yahoo.com> wrote:
>
>(snip, I wrote)
>>>Large model x86, common in the 16 bit days, rare in the 32 bit days,
>>>has a segmented model. I know of a C compiler that will generate
>>>large model x86 code, but no OS to run it on.
> 
>> Any 32-bit version of Windows?  All of which support DOS and Win16
>> applications (including Win10).
>
>Watcom C supports 48 bit pointers, with a 16 bit segment selector
>and 32 bit offset.  It might be that some versions of OS/2 will
>do that, but as far as I know not Windows or Linux.  That is, large
>model 32 bit.


Ah.  I misread your post, and failed to understand that you were
specifically talking about segmented 32-bit code.

[toc] | [prev] | [next] | [standalone]


#74477

From"Morten W. Petersen" <morphex@gmail.com>
Date2015-10-31 20:35 +0100
Message-ID<n13561$7dh$1@speranza.aioe.org>
In reply to#74352
On 30.10.2015 19:16, Keith Thompson wrote:
]....]
> Or you could drop the #defines and just write the second set of code.
>
> If you need to have a whole heck of a lot of distinct invalid non-null
> pointer values, then the first approach could make sense.  On systems
> where relational operators on pointers to distinct objects yield
> consistent results, you could save some execution time.
>
> But I'm having difficulty imagining a realistic scenario where you'd
> actually need such a thing.
>
> For example, C's <signal.h> defines just three distinct pointer values
> that are not necessarily pointers to actual functions: SIG_DFL, SIG_ERR,
> and SIG_IGN (and one of those could be a null pointer).  It doesn't
> provide a single operation equivalent to
>
>      (p == SIG_DFL || p == SIG_ERR || p == SIG_IGN)
>
> probably because (a) it's easy enough to write it yourself if you need
> it and (b) you probably don't need it.
>
> Do you *really* need a large number of distinct non-null pointer values?
> Until you've determined that the answer to that is yes, I suggest not
> worrying about how to implement them.

Yes, I was thinking about whether it was possible, I haven't found any
real use-case where it is a big plus to be able to have a range of
error pointers to return back.

-Morten

[toc] | [prev] | [next] | [standalone]


#74488

Fromsupercat@casperkitty.com
Date2015-10-31 13:33 -0700
Message-ID<5bc9c2b1-02ce-4a2d-93d2-59a823bcff8f@googlegroups.com>
In reply to#74477
On Saturday, October 31, 2015 at 2:35:44 PM UTC-5, Morten W. Petersen wrote:
> Yes, I was thinking about whether it was possible, I haven't found any
> real use-case where it is a big plus to be able to have a range of
> error pointers to return back.

While they wouldn't exactly be "error pointers", there are times when it may
be helpful to have a function which can either return an object taken from
a pool if a suitable one is available, or malloc() a new object otherwise;
being able to have the corresponding "release" function check whether the
object came from the pool without having to spend storage within the object
itself can sometimes be useful.  For example, if a heavily-called function
is supposed to return a string, and 99% of calls will return one of 1473
strings whose total length, including trailing NULs is 24,737 bytes, but
the remaining 1% may return arbitrary strings, it may be helpful to have a char[24737] holding the common strings and a char*[1473] identifying strings
within it, and then be able to return either one of the aforementioned
pointers or a pointer to a new string; when the recipient is done with the
string, however, the function receiving the string back would need to know
whether it needed to call "free" on it.  Adding an extra byte to each
string to indicate whether it was part of the pre-allocated buffer would
not be impossible, but would add an extra 1473 bytes to the pre-allocated
buffer and likely on average add a byte to each allocated string.  Testing
whether each received pointer identified a location within the pre-allocated
string buffer would likely be cheaper.

[toc] | [prev] | [next] | [standalone]


#74389

FromRichard Damon <Richard@Damon-Family.org>
Date2015-10-30 22:19 -0400
Message-ID<azVYx.1052$ma6.941@fx18.iad>
In reply to#74310
On 10/30/15 11:09 AM, Morten W. Petersen wrote:
>
> It also looks like x86 and ARM have a flat memory model, which means
> that the pointer in most cases is a simple non-negative number.
>
> -Morten
>

x86 is not 'flat'. 32 and 64 bit version of it tend to use the 'Tiny' or 
'Small' model (one segment value for everything, at least data) so they 
will look flat.

16 bit x86 often used 'far' pointers (pointers with segment registers) 
which were clearly not flat.

[toc] | [prev] | [next] | [standalone]


#74313

Fromsupercat@casperkitty.com
Date2015-10-30 08:22 -0700
Message-ID<44aec0f4-de7e-4ef5-9357-9ae387e95305@googlegroups.com>
In reply to#74273
On Friday, October 30, 2015 at 6:45:34 AM UTC-5, Richard Damon wrote:
> The practical effect of this is that there are some 
> machines/implementations where you can get false positives, the most 
> notable case is for a machine with segmented pointers where < may only 
> check the offset, and not for the segments to match.

Unfortunately, there is no guarantee that a compiler won't use the fact that
unrelated pointer comparisons yield Undefined Behavior as justification for
assuming that code which compares two pointers can only be reached via path
that would have made those pointers identify parts of the same object.

There are a number of guarantees that many hardware platforms very usefully
provide, and compilers almost always know what guarantees are provided by
the underlying platform (though in some cases a platform may offer stronger
guarantees than a compiler would know about e.g. because memory is so small
that everything has to go in the same segment).  The three most common, in
order of strength:

1. All pointer comparisons will yield a 0 or 1 with no side effect, all
   comparisons define a unique transitive relation, and if p1/p2 and l1/l2
   are the char* start addresses and lengths of a couple of non-overlapping
   objects or portions thereof, then p1 >= p2+l2 or p2 >= p1+l1.

2. All pointer comparisons will yield a 0 or 1 with no side-effects, and
   comparisons define a not-necessarily-unique transitive relation (such
   that an attempt to sort pointers will work, but distinct pointers may
   rank equally).

3. All pointer comparisons will yield a 0 or 1 with no side-effects, but
   there are no guarantees of consistency.

Additional possibilities would be:

4. All comparisons between pointers to unrelated objects will trap in some
   implementation-defined fashion.

5-7. All comparisons between pointers to unrelated object will either trap
     or abide by one of the guarantees 1-3.

8. Any code which compares unrelated pointers may have its functionality
   arbitrarily changed at the whim of the compiler.

The majority of hardware implementations uphold guarantee #1.  I don't think
I've ever used any which couldn't uphold #2.  Unfortunately, if the Standard
doesn't recognize the usefulness of having some platforms expose guarantees
to programmers, I fear there may be a trend toward #8.

[toc] | [prev] | [next] | [standalone]


#74362

FromGeoff <geoff@invalid.invalid>
Date2015-10-30 13:11 -0700
Message-ID<g2j73b92he2n5h3kosotsmqm478tvnitbe@4ax.com>
In reply to#74260
On Fri, 30 Oct 2015 11:05:44 +0100, "Morten W. Petersen"
<morphex@gmail.com> wrote:

>On 30.10.2015 05:48, Robert Wessel wrote:
>[...]
>> IOW, you can't do:
>>
>>    char errors[7];
>>    ...
>>    ptr = somefunc();
>>    if (ptr >= (errors+0)  && ptr <= (errors+6))
>>      handle_errror_1_6();
>>
>> To see if it matches any of those.  If you don't know that the
>> pointers are to the same object, (in)equality is the only thing you
>> can portably test.
>>
>> Basically, don't do that.
>
>OK.  And what does portable mean here?  What are the examples of
>allocating a small array where each member of that array do not have a
>sequential ascending or descending address?
>

It means that NULL is the only pointer value that is guaranteed to
test unequal to any other pointer value of any type. A pointer either
points to an object or it points to NULL. As soon as you start mucking
about with 1, 2, 3, 4... etc, you lose it. Neither are you guaranteed
that those values are invalid pointers across all implementations.
Instead of inventing this pointer-contains-an-error-return, you should
return NULL and if you must, set a global variable of the error code
and let your users inspect that, as I have described previously.

[toc] | [prev] | [next] | [standalone]


#74364

FromGeoff <geoff@invalid.invalid>
Date2015-10-30 13:23 -0700
Message-ID<a6k73bd2uopsoahtttldvlvemb8hfdj24b@4ax.com>
In reply to#74362
On Fri, 30 Oct 2015 13:11:20 -0700, Geoff <geoff@invalid.invalid>
wrote:

>On Fri, 30 Oct 2015 11:05:44 +0100, "Morten W. Petersen"
><morphex@gmail.com> wrote:
>
>>On 30.10.2015 05:48, Robert Wessel wrote:
>>[...]
>>> IOW, you can't do:
>>>
>>>    char errors[7];
>>>    ...
>>>    ptr = somefunc();
>>>    if (ptr >= (errors+0)  && ptr <= (errors+6))
>>>      handle_errror_1_6();
>>>
>>> To see if it matches any of those.  If you don't know that the
>>> pointers are to the same object, (in)equality is the only thing you
>>> can portably test.
>>>
>>> Basically, don't do that.
>>
>>OK.  And what does portable mean here?  What are the examples of
>>allocating a small array where each member of that array do not have a
>>sequential ascending or descending address?
>>
>
>It means that NULL is the only pointer value that is guaranteed to
>test unequal to any other pointer value of any type. A pointer either
>points to an object or it points to NULL. As soon as you start mucking
>about with 1, 2, 3, 4... etc, you lose it. Neither are you guaranteed
>that those values are invalid pointers across all implementations.
>Instead of inventing this pointer-contains-an-error-return, you should
>return NULL and if you must, set a global variable of the error code
>and let your users inspect that, as I have described previously.

Let me put it another way, your users are going to expect to be able
to write:

  ptr = create_xml_parser();

  if(ptr) {
  //use it
  }
  else {
  // oops, ptr==NULL can't use it
  // check an error code for why it failed
  }

Deviate from that paradigm at your own peril.

[toc] | [prev] | [next] | [standalone]


#73506

FromGeoff <geoff@invalid.invalid>
Date2015-10-21 11:13 -0700
Message-ID<29hf2b52iscgg78qeas0kqosnsj31t4t82@4ax.com>
In reply to#73450
On Wed, 21 Oct 2015 07:32:40 +0200, "Morten W. Petersen"
<morphex@gmail.com> wrote:

>What is a real-life example where using 1-7 as pointer return values
>would not work?

I believe your question on this point and your desire to use invalid
pointer values as error return values stems from your inexperience
with C. Relying on a selected range of pointer values is
unconventional and may not be acceptable to potential users of your
library. It is perfectly acceptable to let your library rely on the
standard library functions and their error returns and this is
certainly more portable than inventing some scheme of invalid pointer
values. C guarantees a null pointer is an invalid pointer but AFAIK it
makes no guarantees about any other values and a naive user, not
knowing you're returning a non-null pointer as an error signal, will
be greatly inconvenienced.

So far as you have written your code, the functions in your library
that return pointers only fail when malloc fails and the reason for
malloc failure is already available in the value of errno.

Take your first function as an example (because it's short):

struct parser* create_xml_parser() {
  struct parser* my_parser = 
			(struct parser*)malloc(sizeof(struct parser));
  my_parser->buffer = NULL;
  my_parser->error = NULL;
  return my_parser;
}

You ignore the potential for malloc to fail. If it fails, my_parser ==
NULL and errno will be set. Continuing to process my_parser->buffer
will fail with SIG_SEGV. You, and anyone using your library, will be
wondering why.

Some possible solutions to this problem follow.

1. Pass the NULL return back, let the caller handle errno:
(In other words, design your interface to allow NULL return and insist
that the user deal with that possibility when using the library.)

struct parser* create_xml_parser() {
	struct parser* my_parser = 
			(struct parser*)malloc(sizeof(struct parser));
	if (my_parser) {
		my_parser->buffer = NULL;
		my_parser->error = NULL;
	}
	return my_parser;
}

User writes:
 if(!create_xml_parser)
 ...
 else
 ...

2. Print a diagnostic and return NULL:

struct parser* create_xml_parser() {
	struct parser* my_parser = 
		(struct parser*)malloc(sizeof(struct parser));
	if (my_parser) {
		my_parser->buffer = NULL;
		my_parser->error = NULL;
		return my_parser;
	}
	else {
		printf("Allocation failed: %i\n", errno);
		return my_parser;
	}
}

User still writes:
 if(!create_xml_parser)
 ...
 else
 ...
but your library spews text to stdout.

3. Design your interface to include a status return:
(Let the caller evaluate the return value and provide the place to put
the error status.)

struct parser* create_xml_parser(int *status) {
	struct parser* my_parser = 
		(struct parser*)malloc(sizeof(struct parser));
	if (my_parser) {
		my_parser->buffer = NULL;
		my_parser->error = NULL;
		*status = 0;
	}
	else {
		*status = errno;
	}
	return my_parser;
}

Let the caller evaluate the return value and provide the place to put
the error status. If my_parser == NULL, the user can inspect the
status to see why. If status == ENOMEM he'll know the allocation
failed.

Conversely:

int create_xml_parser(struct parser* my_parser) {
	my_parser = (struct parser*)malloc(sizeof(struct parser));
	if (my_parser) {
		my_parser->buffer = NULL;
		my_parser->error = NULL;
		return 1;
	}
	else 
		return 0;
}

Now the user can write:

if (create_xml_parser(&parser))
...
else
...

[toc] | [prev] | [next] | [standalone]


#73514

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-10-21 20:31 +0100
Message-ID<87r3koggro.fsf@bsb.me.uk>
In reply to#73506
Geoff <geoff@invalid.invalid> writes:
<snip>
> So far as you have written your code, the functions in your library
> that return pointers only fail when malloc fails and the reason for
> malloc failure is already available in the value of errno.

The reason may be available, but the standard does not say that malloc
will set errno.  An implementation is permitted to set errno, but it
doesn't have to.  In effect, you can't do much with it after a call to
malloc fails in portable code.

<snip>
> 3. Design your interface to include a status return:
> (Let the caller evaluate the return value and provide the place to put
> the error status.)
>
> struct parser* create_xml_parser(int *status) {
> 	struct parser* my_parser = 
> 		(struct parser*)malloc(sizeof(struct parser));
> 	if (my_parser) {
> 		my_parser->buffer = NULL;
> 		my_parser->error = NULL;
> 		*status = 0;
> 	}
> 	else {
> 		*status = errno;
> 	}
> 	return my_parser;
> }

Another related option: given that most (all?) of the functions will
(should?) take a struct parser * argument, the status of the call could
be stored there.  To solve the "bootstrap" problem, create_xml_parser
can return a pointer to a static object with error_code == NoMemory.

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#73554

FromGeoff <geoff@invalid.invalid>
Date2015-10-22 07:13 -0700
Message-ID<a3rh2bpjspm8v8rhl8en2ukiktbrbh1qb6@4ax.com>
In reply to#73514
On Wed, 21 Oct 2015 20:31:39 +0100, Ben Bacarisse
<ben.usenet@bsb.me.uk> wrote:

>Geoff <geoff@invalid.invalid> writes:
><snip>
>> So far as you have written your code, the functions in your library
>> that return pointers only fail when malloc fails and the reason for
>> malloc failure is already available in the value of errno.
>
>The reason may be available, but the standard does not say that malloc
>will set errno.  An implementation is permitted to set errno, but it
>doesn't have to.  In effect, you can't do much with it after a call to
>malloc fails in portable code.
>
><snip>
>> 3. Design your interface to include a status return:
>> (Let the caller evaluate the return value and provide the place to put
>> the error status.)
>>
>> struct parser* create_xml_parser(int *status) {
>> 	struct parser* my_parser = 
>> 		(struct parser*)malloc(sizeof(struct parser));
>> 	if (my_parser) {
>> 		my_parser->buffer = NULL;
>> 		my_parser->error = NULL;
>> 		*status = 0;
>> 	}
>> 	else {
>> 		*status = errno;
>> 	}
>> 	return my_parser;
>> }
>
>Another related option: given that most (all?) of the functions will
>(should?) take a struct parser * argument, the status of the call could
>be stored there.  To solve the "bootstrap" problem, create_xml_parser
>can return a pointer to a static object with error_code == NoMemory.
>
><snip>

Which is why I'd be inclined to use example #1 over the others. Return
NULL in the event of failure just as malloc does. Let the user of the
library handle errno if it's set on his system. Implement the library
in a standard way and don't surprise the user with non-null pointers
that are supposed to indicate errors. I would not recommend as you
suggest that if the instantiation of the parser object fails that it
return a valid pointer to some error object, this is needless
complexity. 

[toc] | [prev] | [next] | [standalone]


#73823

From"Morten W. Petersen" <morphex@gmail.com>
Date2015-10-26 07:16 +0100
Message-ID<n0kggd$6gh$1@speranza.aioe.org>
In reply to#73506
On 21.10.2015 20:13, Geoff wrote:
> On Wed, 21 Oct 2015 07:32:40 +0200, "Morten W. Petersen"
> <morphex@gmail.com> wrote:
>
>> What is a real-life example where using 1-7 as pointer return values
>> would not work?
[...]
> So far as you have written your code, the functions in your library
> that return pointers only fail when malloc fails and the reason for
> malloc failure is already available in the value of errno.
>
> Take your first function as an example (because it's short):
>
> struct parser* create_xml_parser() {
>    struct parser* my_parser =
> 			(struct parser*)malloc(sizeof(struct parser));
>    my_parser->buffer = NULL;
>    my_parser->error = NULL;
>    return my_parser;
> }
>
> You ignore the potential for malloc to fail. If it fails, my_parser ==
> NULL and errno will be set. Continuing to process my_parser->buffer
> will fail with SIG_SEGV. You, and anyone using your library, will be
> wondering why.
>
> Some possible solutions to this problem follow.
>
> 1. Pass the NULL return back, let the caller handle errno:
> (In other words, design your interface to allow NULL return and insist
> that the user deal with that possibility when using the library.)
>
> struct parser* create_xml_parser() {
> 	struct parser* my_parser =
> 			(struct parser*)malloc(sizeof(struct parser));
> 	if (my_parser) {
> 		my_parser->buffer = NULL;
> 		my_parser->error = NULL;
> 	}
> 	return my_parser;
> }

I've been thinking that a variant of this is the best way to go, but
that an error is set on the parser object.  But that won't work if
malloc fails and there is no parser object in memory.

But I see that the 3rd example uses a status pointer, but again, how
would all of this work if one runs out of memory when calling the
function?

Is it better to allocate memory for the struct before the initialization
happens?

-Morten

[toc] | [prev] | [next] | [standalone]


#73831

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2015-10-26 09:37 +0000
Message-ID<slrnn2rt3l.5q5.grahn+nntp@frailea.sa.invalid>
In reply to#73823
On Mon, 2015-10-26, Morten W. Petersen wrote:
> On 21.10.2015 20:13, Geoff wrote:
>> On Wed, 21 Oct 2015 07:32:40 +0200, "Morten W. Petersen"
>> <morphex@gmail.com> wrote:
>>
>>> What is a real-life example where using 1-7 as pointer return values
>>> would not work?
> [...]
>> So far as you have written your code, the functions in your library
>> that return pointers only fail when malloc fails and the reason for
>> malloc failure is already available in the value of errno.
>>
>> Take your first function as an example (because it's short):
>>
>> struct parser* create_xml_parser() {
>>    struct parser* my_parser =
>> 			(struct parser*)malloc(sizeof(struct parser));
>>    my_parser->buffer = NULL;
>>    my_parser->error = NULL;
>>    return my_parser;
>> }
>>
>> You ignore the potential for malloc to fail. If it fails, my_parser ==
>> NULL and errno will be set. Continuing to process my_parser->buffer
>> will fail with SIG_SEGV. You, and anyone using your library, will be
>> wondering why.
>>
>> Some possible solutions to this problem follow.
>>
>> 1. Pass the NULL return back, let the caller handle errno:
>> (In other words, design your interface to allow NULL return and insist
>> that the user deal with that possibility when using the library.)
>>
>> struct parser* create_xml_parser() {
>> 	struct parser* my_parser =
>> 			(struct parser*)malloc(sizeof(struct parser));
>> 	if (my_parser) {
>> 		my_parser->buffer = NULL;
>> 		my_parser->error = NULL;
>> 	}
>> 	return my_parser;
>> }
>
> I've been thinking that a variant of this is the best way to go, but
> that an error is set on the parser object.  But that won't work if
> malloc fails and there is no parser object in memory.
>
> But I see that the 3rd example uses a status pointer, but again, how
> would all of this work if one runs out of memory when calling the
> function?
>
> Is it better to allocate memory for the struct before the initialization
> happens?

I think that is what I prefer: that the user is responsible for having
a struct Parser, and calling parser_init() on it.  It's the difference
between these two:

  bool foo_init(struct Foo*, ...);
  struct Foo* foo_create(...);

The latter one lets you hide the contents of struct Foo from users,
but you're forcing heap allocation on them, and you can't easily tell
them why creation failed.

Heap allocation is not a big problem here, but if Foo is a "class"
which is small and used a lot, it gets tedious and inefficient.
Imagine storing all ints in a program on the heap ...

/Jorgen

-- 
  // Jorgen Grahn <grahn@ Oo o.  .  .  \X/ snipabacken.se> O o .

[toc] | [prev] | [next] | [standalone]


#73532

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2015-10-22 05:38 +0000
Message-ID<n09sod$e2a$1@speranza.aioe.org>
In reply to#73450
Morten W. Petersen <morphex@gmail.com> wrote:
> On 19.10.2015 17:59, Keith Thompson wrote:

(snip)

>> Not 100% portably.  A small non-zero integer converted to a pointer
>> type is unlikely to match a valid pointer value, but there's no
>> guarantee.  Even accessing an invalid pointer (without dereferencing
>> it) can have undefined behavior.
 
> Hmm, OK.  That dereferencing wouldn't work was expected, but why would
> working with an address value not work?
 
> What is a real-life example where using 1-7 as pointer return values
> would not work?

C guarantees that no valid pointer will have the value equal to a null
pointer.

On small systems, or larger systems in small memory model, C has to
guarantee that no pointer is NULL, so won't ever use the otherwise
valid pointer (void*)0.  C doesn't guarantee that no pointer is
equal to (void*)1. 

Also, as previously noted, using <, <=, >, >=, might give surprising
results.

-- glen

[toc] | [prev] | [next] | [standalone]


#73546

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-10-22 13:51 +0100
Message-ID<87a8rbgj6v.fsf@bsb.me.uk>
In reply to#73532
glen herrmannsfeldt <gah@ugcs.caltech.edu> writes:

> Morten W. Petersen <morphex@gmail.com> wrote:
>> On 19.10.2015 17:59, Keith Thompson wrote:
>
> (snip)
>
>>> Not 100% portably.  A small non-zero integer converted to a pointer
>>> type is unlikely to match a valid pointer value, but there's no
>>> guarantee.  Even accessing an invalid pointer (without dereferencing
>>> it) can have undefined behavior.
>  
>> Hmm, OK.  That dereferencing wouldn't work was expected, but why would
>> working with an address value not work?
>  
>> What is a real-life example where using 1-7 as pointer return values
>> would not work?
>
> C guarantees that no valid pointer will have the value equal to a null
> pointer.
>
> On small systems, or larger systems in small memory model, C has to
> guarantee that no pointer is NULL, so won't ever use the otherwise
> valid pointer (void*)0.  C doesn't guarantee that no pointer is
> equal to (void*)1.

... or even, just to be clear, that (void*)0 != (void*)1.

Whilst that's covered by your "no pointer is equal to (void*)1" wording,
you also say that "no pointer is NULL" so I think you are using "no
pointer" to mean "no valid object or function pointer".

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


Page 3 of 4 — ← Prev page 1 2 [3] 4  Next page →

Back to top | Article view | comp.lang.c


csiph-web