Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > 2D arrays, pointers, and pointer arithmetic: question

Reply
Thread Tools

2D arrays, pointers, and pointer arithmetic: question

 
 
James Kuyper
Guest
Posts: n/a
 
      08-29-2012
On 08/29/2012 04:05 PM, Edward Rutherford wrote:
> Keith Thompson wrote:
>> `near` and `far`, which are of course non-standard, can result in
>> different pointer types having different sizes. Passing a `near` or
>> `far` pointer to printf with a "%p" format is likely to give bad results
>> in practice.

>
> Using near or far pointers in any way at all will invoke an undefined
> behavior, so I think it's safe to say bad results are likely with or
> without attempts to printf() such pointers!


Within the context of the C standard, "undefined behavior" means only
that the C standard doesn't define the behavior. If the compiler's
documentation does define the behavior, you should be OK, even if the C
standard doesn't.

However, it's extremely unlikely that a compiler which supports both
near and far pointers would come along with a C standard library who's
printf() allows you to print both types of pointers with the same "%p"
format specifier. That's the "bad results in practice" that he was
talking about.
 
Reply With Quote
 
 
 
 
Keith Thompson
Guest
Posts: n/a
 
      08-30-2012
Edward Rutherford <(E-Mail Removed)> writes:
> Keith Thompson wrote:
>> `near` and `far`, which are of course non-standard, can result in
>> different pointer types having different sizes. Passing a `near` or
>> `far` pointer to printf with a "%p" format is likely to give bad results
>> in practice.

>
> Using near or far pointers in any way at all will invoke an undefined
> behavior, so I think it's safe to say bad results are likely with or
> without attempts to printf() such pointers!


For a C implementation that supports `near`, `far`, `void*`, and
printf's "%p" format, I would expect that casting a `near` or `far`
pointer value to `void*` before passing it to printf would work
"correctly". Of course the standard doesn't guarantee that, but I'd
expect it of any decent C or C-like implementation.

(I've never used `near` or `far` myself. It's plausible that an
implementation old enough to support them would be too old to support
`void*`.)

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
 
Les Cargill
Guest
Posts: n/a
 
      08-30-2012
Keith Thompson wrote:
> Edward Rutherford <(E-Mail Removed)> writes:
>> Keith Thompson wrote:
>>> `near` and `far`, which are of course non-standard, can result in
>>> different pointer types having different sizes. Passing a `near` or
>>> `far` pointer to printf with a "%p" format is likely to give bad results
>>> in practice.

>>
>> Using near or far pointers in any way at all will invoke an undefined
>> behavior, so I think it's safe to say bad results are likely with or
>> without attempts to printf() such pointers!

>
> For a C implementation that supports `near`, `far`, `void*`, and
> printf's "%p" format, I would expect that casting a `near` or `far`
> pointer value to `void*` before passing it to printf would work
> "correctly". Of course the standard doesn't guarantee that, but I'd
> expect it of any decent C or C-like implementation.
>
> (I've never used `near` or `far` myself. It's plausible that an
> implementation old enough to support them would be too old to support
> `void*`.)
>



The C89 flavors of MSC supported both "void*" and "near"/"far". TINY
MODEL FTW!

--
Les Cargill
 
Reply With Quote
 
ais523
Guest
Posts: n/a
 
      08-30-2012
Keith Thompson wrote:
> (I've never used `near` or `far` myself. It's plausible that an
> implementation old enough to support them would be too old to support
> `void*`.)


16-bit versions of Borland C for Windows supported void* just fine
(we're talking well after 1989; they ran under Windows 95 to be able to
compile programs that would run under the still-then-in-use Windows
3.1), but also supported near and far because they existed on that
platform.

The fix used for standards compliance was to have compiler options to
specify whether function pointers were near/far if not specified, and
whether non-function pointers were near/far if not specified. (This
means, among other things, that it was not necessarily possible to
convert a void(*)() to a void* and back again, which makes for a nice
counterexample to give to people who think it is possible.) The system
headers marked every pointer with near or far in order to make them
conform to the library ABI, and implicit casts were added to the
language avoid this causing trouble.

There was actually a third option, huge, which could cope with objects
larger than one segment (by performing extra arithmetic upon segment
overflow), and was otherwise like far. (And was rarely used, because
objects that large were not so useful back then due to limited memory.)
I also remember the system-specific library function farmalloc(), which
was like malloc but which gave you a far pointer; very useful for
storing large amounts of data long-term in a program which otherwise
could do with near pointers for data.

--
ais523
 
Reply With Quote
 
Malcolm McLean
Guest
Posts: n/a
 
      08-30-2012
בתאריך יום חמישי, 30 באוגוסט 2012 02:09:02 UTC+1, מאת Les Cargill:
> Keith Thompson wrote:
>
> The C89 flavors of MSC supported both "void*" and "near"/"far". TINY
> MODEL FTW!
>

The idea of the "models" was that you could write program without the
near/far non-standard extensions. Under "huge", if I remember rightly,
all pointers were 32 bit and it did some inefficient magic to hide the
segments and give you what looked like flat memory. Under "large",
pointers were 32 bits but you couldn't allocate a block of more than
64 K.
Under "tiny" all code and data had to fit within the same 64K segment,
which led to the most efficient machine code. But you could use far
pointers to allocate data in other segments. So you ended up rewriting
fucntions like "farmemcpy", because the standard library only worked
with the standard pointers.




 
Reply With Quote
 
ralph
Guest
Posts: n/a
 
      08-30-2012
On Wed, 29 Aug 2012 11:37:02 -0700, Keith Thompson <(E-Mail Removed)>
wrote:

>Eric Sosman <(E-Mail Removed)> writes:
>> On 8/29/2012 3:20 AM, Adrian Ratnapala wrote:
>>> [... about converting int* to void* for "%p" conversion ...]
>>> BTW: I don't know if my misconception is "frequent" enough to warrant an
>>> FAQ change, but it doesn't look like the FAQ covers this. Contra Eric,
>>> 5.17 is about something else; 4.17 / 19.40 are closer but not quite
>>> relevant.

>>
>> 5.17 is mostly about representations of null pointers, but
>> not entirely. If you'll read the entire thing, you'll find two
>> specific mentions of different pointer formats, plus a link to
>> further examples.
>>
>> 14.17 and 19.40(d) are about `near' and `far', whose
>> connection to the matter at hand eludes me.

>
>`near` and `far`, which are of course non-standard, can result in
>different pointer types having different sizes. Passing a `near`
>or `far` pointer to printf with a "%p" format is likely to give
>bad results in practice.


Actually in practice it was never an issue.

Because of how the different models were implemented a different CRT
or "standard C Library" was always employed, thus each encountered a
"printf()" fully able to managed whatever "%p" formatted argument it
received.

-ralph
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      08-30-2012
ralph <(E-Mail Removed)> writes:
> On Wed, 29 Aug 2012 11:37:02 -0700, Keith Thompson <(E-Mail Removed)>
> wrote:

[...]
>>`near` and `far`, which are of course non-standard, can result in
>>different pointer types having different sizes. Passing a `near`
>>or `far` pointer to printf with a "%p" format is likely to give
>>bad results in practice.

>
> Actually in practice it was never an issue.
>
> Because of how the different models were implemented a different CRT
> or "standard C Library" was always employed, thus each encountered a
> "printf()" fully able to managed whatever "%p" formatted argument it
> received.


Wasn't it possible to have both near and far pointers, with different
sizes, in the same program?

For example:

char near *nearp = ...;
char far *farp = ...;
printf("nearp = %p, farp = %p\n", nearp, farp);

Maybe that wasn't a common thing to do, but wouldn't it cause problems?

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Anders Wegge Keller
Guest
Posts: n/a
 
      08-30-2012
Keith Thompson <(E-Mail Removed)> writes:

> Wasn't it possible to have both near and far pointers, with
> different sizes, in the same program?


It is. The 80186 compiler I use at work calls this "Mixed mode".

> For example:
>
> char near *nearp = ...;
> char far *farp = ...;
> printf("nearp = %p, farp = %p\n", nearp, farp);
>
> Maybe that wasn't a common thing to do, but wouldn't it cause problems?


One should think that this would give a funny-looking result for the
near pointer. But I've never had to log pointer values on that
platform, so I cannot say for sure what would happen.

--
/Wegge

Leder efter redundant peering af dk.*,linux.debian.*
 
Reply With Quote
 
ralph
Guest
Posts: n/a
 
      08-31-2012
On Thu, 30 Aug 2012 13:52:06 -0700, Keith Thompson <(E-Mail Removed)>
wrote:

>ralph <(E-Mail Removed)> writes:
>> On Wed, 29 Aug 2012 11:37:02 -0700, Keith Thompson <(E-Mail Removed)>
>> wrote:

>[...]
>>>`near` and `far`, which are of course non-standard, can result in
>>>different pointer types having different sizes. Passing a `near`
>>>or `far` pointer to printf with a "%p" format is likely to give
>>>bad results in practice.

>>
>> Actually in practice it was never an issue.
>>
>> Because of how the different models were implemented a different CRT
>> or "standard C Library" was always employed, thus each encountered a
>> "printf()" fully able to managed whatever "%p" formatted argument it
>> received.

>
>Wasn't it possible to have both near and far pointers, with different
>sizes, in the same program?
>
>For example:
>
> char near *nearp = ...;
> char far *farp = ...;
> printf("nearp = %p, farp = %p\n", nearp, farp);
>
>Maybe that wasn't a common thing to do, but wouldn't it cause problems?


Not in "common practice" since the keywords "far" and "near" were
themselves implementaton and conditionally defined. ie, "far" was
actually a defined macro "__far"*.

It was essentially difficult to create 'near' and 'far' pointers in
the same translation unit without going out of your way to contrive
something.

char near *nearp = ...;
char far *farp = ...;

I would expect the above to silent or deliver a strong Warning or even
Error, depending on model being compiled.

Of course we are talking about more than a vendor extension to the
language. Microsoft besides simply providing two different sized
pointer declarations also did thunking and other redefinitions behind
the scenes. (Both the preprocessor and linker were very busy little
beavers. <g>) For example, 'near' pointers magically became 'far'
pointers when calling something in a 'WinAPI' shared library. Well not
too much magic. They basically just prefixed the current defaut
segment to the near address. Hard to say what else might have been
going on. Can't remember all of it.

Do remember that it 'just worked'. <g>

-ralph
[__far* Originally it was "_far", one under-score. Later it become
"__far" to be ANSI compliant for vendor implementation defines. The
final definition was often buried in a stack of #defines. <g>]
 
Reply With Quote
 
Richard Damon
Guest
Posts: n/a
 
      09-02-2012
On 8/30/12 7:47 AM, Malcolm McLean wrote:
> בתאריך יום חמישי, 30 באוגוסט 2012 02:09:02 UTC+1, מאת Les Cargill:
>> Keith Thompson wrote:
>>
>> The C89 flavors of MSC supported both "void*" and "near"/"far". TINY
>> MODEL FTW!
>>

> The idea of the "models" was that you could write program without the
> near/far non-standard extensions. Under "huge", if I remember rightly,
> all pointers were 32 bit and it did some inefficient magic to hide the
> segments and give you what looked like flat memory. Under "large",
> pointers were 32 bits but you couldn't allocate a block of more than
> 64 K.
> Under "tiny" all code and data had to fit within the same 64K segment,
> which led to the most efficient machine code. But you could use far
> pointers to allocate data in other segments. So you ended up rewriting
> fucntions like "farmemcpy", because the standard library only worked
> with the standard pointers.
>
>
>
>


The models came about due to the memory structure of the 16 bit x86
architecture. Addresses were in general greater than 16 bits in length,
while address registers were only 16 bits long, and were combined with a
"segment register" to convert the value to a full address. (depending on
what mode the processor was in would change how the conversion was done).

Near pointers only stored the value of the address register, and the
segment register was assumed by the type of pointer (the Data Segment
Register for "data" pointers, and the Program Segment Register for
function pointers). In addition, data pointers had a huge type, which
was like a far pointer, but could point to an object that might be
bigger than a single segment, and the compiler would need to do
additional work on address arithmetic to handle this. It mostly was used
in "Real" mode, where the Segment register was just added to the address
register after shifting up the Segment register 4 bits (giving a 20 bit
final memory address).

The program model determined what were the default sizes for each type
of pointer.

Model Data Code
Tiny near near
Small near near
Medium near far
Compact far near
Large far far
Huge huge far

The difference between Tiny and Small was that in Tiny, the code and
data were in the same segment, while in Small they were in distinct
segments.

It was by far more common to have near/far pointers in code that had a
default near size of pointers, to handle a limited number of
objects/functions that would be placed outside the default near block to
make room for them, sometimes to access things outside the current program.

Note also that the 32 bit x86 family of processors still have these
memory models (and 48 bit "far" pointers), they are just mostly ignored
and most programs are just done in the Tiny or Small model, after all
who should need more than 4GB of address space The resurgence of
memory models for programs was headed off (for now at least) with the
introduction of 64 bit processors.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointer to an array vs pointer to pointer subramanian100in@yahoo.com, India C Programming 5 09-23-2011 10:28 AM
Pointer to pointer or reference to pointer A C++ 7 07-05-2011 07:49 PM
Pointer to pointer Vs References to Pointer bansalvikrant@gmail.com C++ 4 07-02-2009 10:20 AM
passing the address of a pointer to a func that doesnt recieve a pointer-to-a-pointer jimjim C Programming 16 03-27-2006 11:03 PM
Pointer-to-pointer-to-pointer question masood.iqbal@lycos.com C Programming 10 02-04-2005 02:57 AM



Advertisments