va_arg and short

  • Thread starter Glen Herrmannsfeldt
  • Start date
L

lawrence.jones

In comp.std.c Douglas A. Gwyn said:
You can use fgetpos/fsetpos for many such purposes, but there
is no standard way to perform arithmetic on those offset
cookies.

There is, but it's ugly:

/* add n to pos */
fsetpos(f, pos);
fseek(f, n, SEEK_CUR);
fgetpos(f, &pos);

-Larry Jones

Monopoly is more fun when you make your own Chance cards. -- Calvin
 
J

James Kuyper

Douglas A. Gwyn said:
Most programmers don't try to create objects so large that
they have to worry about SIZE_MAX. If you do have to worry,
use a method like what Francis showed.

Many of the programs I've work on over the past 20 years have pushed the
limit on available memory, and in several cases they pushed the limit on
what C99 would call SIZE_MAX (though most of them have been C90
programs). I have no idea how common that is; it may be more common in
the kind of applications I work on than in other kinds you're more
familiar with.
 
D

Dave Thompson

Well, that is a good question. Maybe 16 bit int is long past, and we
shouldn't worry about the problem. Though with 32 bit int and memories
larger than 4GB maybe we should. Consider a machine with 64 bit pointers,
but 32 bit int. You could still increment the pointer multiple times, less
than 2GB each time. Now, reasonably likely the machine would also have a
64 bit long or long long, but maybe doesn't supply the ability to increment
pointers (or subscript arrays) with them.
Then it's nonconforming. Pointer arithmetic is defined for any integer
type (in C99 including any implementation-defined 'extended' types)
not just 'int'. But only within one declared or allocated object,
whose size apparently can be bounded by size_t -- especially if, say,
the actual address space usable without thrashing is only say 10GB,
even though represented in a 64bit format, and address calculations
using >32bit offset are more costly, it might well be a reasonable
tradeoff to support only 4G-1B objects in that address space, and
*then* only subscripting/offseting by up to that. Or maybe even 2G-1B,
so ptrdiff_t can be 32bit signed.

Well, the argument of fseek() and the return from ftell() were long (or even
int?) many years before 4GB of memory was affordable, real or virtual. It
looks like a mistake now, and then we have things like fseek64() and
ftell64().
More to the point, before 4GB in a single disk; or really filesystem,
which then was at most one disk. Heck, 6ed Unix ran on a system with
5*M*B of disk (2 x RK05, and that's cartridge not the wuss -F).


- David.Thompson1 at worldnet.att.net
 
G

glen herrmannsfeldt

Dave said:
On Tue, 11 Nov 2003 08:40:02 GMT, "Glen Herrmannsfeldt"
(snip)
Then it's nonconforming. Pointer arithmetic is defined for any integer
type (in C99 including any implementation-defined 'extended' types)
not just 'int'. But only within one declared or allocated object,
whose size apparently can be bounded by size_t -- especially if, say,
the actual address space usable without thrashing is only say 10GB,
even though represented in a 64bit format, and address calculations
using >32bit offset are more costly, it might well be a reasonable
tradeoff to support only 4G-1B objects in that address space, and
*then* only subscripting/offseting by up to that. Or maybe even 2G-1B,
so ptrdiff_t can be 32bit signed.

Can an implementation have 64 bit pointers, but no integer type longer
than 32 bits?

How do you make a constant of type size_t?

-- glen
 
D

Dan Pop

In said:
Can an implementation have 64 bit pointers, but no integer type longer
than 32 bits?

Yes, of course, as far as C89 is concerned. C99 requires long long to be
at least 64-bit.
How do you make a constant of type size_t?

You don't. But you can have a constant expression of type size_t and
constant expressions can be used instead of constants anywhere. E.g.
a C89 program can define SIZE_MAX as (size_t)-1.

Dan
 
C

CBFalconer

glen said:
.... snip ...

Can an implementation have 64 bit pointers, but no integer type
longer than 32 bits?

Of course. You see it every day on your garden variety x86
machines. Every pointer involves a segment register value, all of
which just happen to be set the same, and thus effectively
ignored.
 
R

Richard Tobin

CBFalconer said:
Of course. You see it every day on your garden variety x86
machines. Every pointer involves a segment register value, all of
which just happen to be set the same, and thus effectively
ignored.

That's silly. You might as well say that all pointers include the
page table. The implementation of dereferencing pointers involves the
segment registers, but they are not part of the pointer. If they were,
you'd be able to alter a pointer to include a different segment
register - by abuse of pointers to pointers, or by using a debugger -
and you can't.

-- Richard
 
C

CBFalconer

Richard said:
That's silly. You might as well say that all pointers include the
page table. The implementation of dereferencing pointers involves the
segment registers, but they are not part of the pointer. If they were,
you'd be able to alter a pointer to include a different segment
register - by abuse of pointers to pointers, or by using a debugger -
and you can't.

Yes you can. Just use a debugger that can alter the segment
registers and operates at machine code level. Just before a
dereference alter the implied segment register for that
instruction.

For a safer simulation just use some compact model MSDOS code
under debug, and alter the segment registers. Just because people
have gone to great lengths to hide the unpleasant truths from you
doesn't mean they don't exist.
 
R

Richard Tobin

CBFalconer said:
Yes you can. Just use a debugger that can alter the segment
registers and operates at machine code level. Just before a
dereference alter the implied segment register for that
instruction.

And integers are all 33 bits. Just before an addition, alter the
carry flag.

-- Richard
 
G

glen herrmannsfeldt

Micah said:
(size_t) 100

I was thinking about (size_t) 1000000 or maybe (size_t) 3000000000

but you don't know if INT_MAX or even LONG_MAX is big enough.

Maybe an S suffix for size_t constants?

-- glen
 
G

glen herrmannsfeldt

Richard said:
That's silly. You might as well say that all pointers include the
page table. The implementation of dereferencing pointers involves the
segment registers, but they are not part of the pointer. If they were,
you'd be able to alter a pointer to include a different segment
register - by abuse of pointers to pointers, or by using a debugger -
and you can't.

Well, there are compilers that support 48 bit pointers, with a segment
selector and 32 bit offset. They are rare, though, and I don't think
support huge model where overflowing offset increments the selector.

With the AMD 64 bit processors things may change.

-- glen
 
A

Andreas Schwab

glen herrmannsfeldt said:
I was thinking about (size_t) 1000000 or maybe (size_t) 3000000000

but you don't know if INT_MAX or even LONG_MAX is big enough.

(size_t) 1000 * (size_t) 1000

Andreas.
 
D

Dan Pop

In said:
Of course. You see it every day on your garden variety x86
machines. Every pointer involves a segment register value, all of
which just happen to be set the same, and thus effectively
ignored.

In which case, they are not part of the pointer value, as far as any
correct C program is concerned.

It's the same with the tiny and small memory models of the 8086: they
had 16-bit pointers, although the processor used 20-bit addresses.

Dan
 
D

Dan Pop

In said:
I was thinking about (size_t) 1000000 or maybe (size_t) 3000000000

but you don't know if INT_MAX or even LONG_MAX is big enough.

It doesn't matter: the type of 1000000 or 3000000000 is automatically
chosen by the compiler to accomodate the value of the constant, if such
a type exists:

5 The type of an integer constant is the first of the corresponding
list in which its value can be represented.

|| |
|| | Octal or Hexadecimal
Suffix || Decimal Constant | Constant
-------------++-----------------------+------------------------
none ||int | int
||long int | unsigned int
||long long int | long int
|| | unsigned long int
|| | long long int
|| | unsigned long long int
-------------++-----------------------+------------------------
u or U ||unsigned int | unsigned int
||unsigned long int | unsigned long int
||unsigned long long int | unsigned long long int
-------------++-----------------------+------------------------
l or L ||long int | long int
||long long int | unsigned long int
|| | long long int
|| | unsigned long long int
-------------++-----------------------+------------------------
Both u or U ||unsigned long int | unsigned long int
and l or L ||unsigned long long int | unsigned long long int
-------------++-----------------------+------------------------
ll or LL ||long long int | long long int
|| | unsigned long long int
-------------++-----------------------+------------------------
Both u or U ||unsigned long long int | unsigned long long int
and ll or LL || |

If an integer constant cannot be represented by any type in
its list, it may have an extended integer type, if the extended
integer type can represent its value. If all of the types in the
list for the constant are signed, the extended integer type shall
be signed. If all of the types in the list for the constant are
unsigned, the extended integer type shall be unsigned. If the
list contains both signed and unsigned types, the extended
integer type may be signed or unsigned.

This effectively guarantees that, if 3000000000000000000000000 is
a supported value for the type size_t, (size_t) 3000000000000000000000000
will give you the right thing, even if there is no standard integer type
that can represent 3000000000000000000000000 (size_t will be an alias for
an extended integer type, in this case).
Maybe an S suffix for size_t constants?

What problem would such a suffix solve that a cast to size_t wouldn't?

Dan
 
D

Dan Pop

In said:
(size_t) 1000 * (size_t) 1000

Name ONE scenario where (size_t) 1000 * (size_t) 1000 works better than
(size_t) 1000000.

Here's one scenarion where (size_t) 1000 * (size_t) 1000 invokes undefined
behaviour, but (size_t) 1000000 doesn't:

#typedef unsigned short size_t
#define USHRT_MAX 65535
#define INT_MAX 131071

Dan
 
C

CBFalconer

glen said:
I was thinking about (size_t) 1000000 or maybe (size_t) 3000000000

but you don't know if INT_MAX or even LONG_MAX is big enough.

I believe size_t is specified to be an integral type, and the
largest integral type is long (in C90) or long long (in C99).
 
E

Eric Sosman

CBFalconer said:
I believe size_t is specified to be an integral type, and the
largest integral type is long (in C90) or long long (in C99).

size_t is integral, and unsigned as well.

C90 defines nine integer types (plain char plus signed
and unsigned versions of char, short, int, and long). The
list is complete; no implementation-provided extra type is
considered an "integer." Thus, size_t is a synonym for one
of the four or five unsigned types.

C99 adds long long, raising the census of standard
integer types to eleven and the number of standard size_t
candidate types to five or six. But C99 also introduces
optional "extended" integer types, and as far as I can
tell it is permissible for size_t to be an extended type.
In C99, `unsigned long long' might not be wide enough for
all size_t values. `uintmax_t' will work, of course.
 
D

Douglas A. Gwyn

CBFalconer said:
I believe size_t is specified to be an integral type, and the
largest integral type is long (in C90) or long long (in C99).

Those are the widest *standard* integer types.
An implementation can also support extended integer types,
and as of C99 we officially permit them to be used for size_t etc.
 
J

James Kuyper

CBFalconer said:
I believe size_t is specified to be an integral type, and the
largest integral type is long (in C90) or long long (in C99).

More precisely, size_t is specified as being an unsigned integral type.
The largest unsigned integral type is indeed 'unsigned long' in C90, but
it is 'uintmax_t' in C99, which might be larger than 'unsigned long
long'. The only requirements on size_t are UCHAR_MAX<=SIZE_MAX &&
SIZE_MAX<=UINTMAX_MAX.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top