Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #63510 > unrolled thread
| Started by | Rahul Kumar <rahulkumar5july@gmail.com> |
|---|---|
| First post | 2015-06-18 06:45 -0700 |
| Last post | 2015-06-18 10:14 -0700 |
| Articles | 19 — 7 participants |
Back to article view | Back to comp.lang.c
What is the output of this program ? Rahul Kumar <rahulkumar5july@gmail.com> - 2015-06-18 06:45 -0700
Re: What is the output of this program ? James Kuyper <jameskuyper@verizon.net> - 2015-06-18 10:10 -0400
Re: What is the output of this program ? Richard Heathfield <rjh@cpax.org.uk> - 2015-06-18 15:22 +0100
Re: What is the output of this program ? Keith Thompson <kst-u@mib.org> - 2015-06-18 08:07 -0700
Re: What is the output of this program ? Richard Heathfield <rjh@cpax.org.uk> - 2015-06-18 16:11 +0100
Re: What is the output of this program ? Ralf Damaschke <rwspam@gmx.de> - 2015-06-18 18:48 +0000
Re: What is the output of this program ? Richard Heathfield <rjh@cpax.org.uk> - 2015-06-18 23:01 +0100
Re: What is the output of this program ? Tim Rentsch <txr@alumni.caltech.edu> - 2015-07-11 08:31 -0700
Re: What is the output of this program ? jadill33@gmail.com - 2015-07-13 07:51 -0700
Re: What is the output of this program ? Tim Rentsch <txr@alumni.caltech.edu> - 2015-07-15 02:51 -0700
Re: What is the output of this program ? jadill33@gmail.com - 2015-07-15 05:55 -0700
Re: What is the output of this program ? Tim Rentsch <txr@alumni.caltech.edu> - 2015-07-20 10:01 -0700
Re: What is the output of this program ? Richard Heathfield <rjh@cpax.org.uk> - 2015-07-13 22:07 +0100
Re: What is the output of this program ? Keith Thompson <kst-u@mib.org> - 2015-07-13 14:16 -0700
Re: What is the output of this program ? Tim Rentsch <txr@alumni.caltech.edu> - 2015-07-15 02:11 -0700
Re: What is the output of this program ? Richard Heathfield <rjh@cpax.org.uk> - 2015-07-15 10:58 +0100
Re: What is the output of this program ? Tim Rentsch <txr@alumni.caltech.edu> - 2015-07-20 10:05 -0700
Re: What is the output of this program ? James Kuyper <jameskuyper@verizon.net> - 2015-06-18 12:26 -0400
Re: What is the output of this program ? Keith Thompson <kst-u@mib.org> - 2015-06-18 10:14 -0700
| From | Rahul Kumar <rahulkumar5july@gmail.com> |
|---|---|
| Date | 2015-06-18 06:45 -0700 |
| Subject | What is the output of this program ? |
| Message-ID | <b3e47c82-8ba3-4d5d-bf40-6f87a390b15a@googlegroups.com> |
#include <stdio.h>
struct s
{
int a:4;
char b:5;
int c:7;
unsigned f1:1;
unsigned f2:24;
unsigned :3;
int :3;// anonymous b.f. -- not accessible
int :0; // significance -- align to next word boundary -- 47 bit < 64 bit -- align to 64 bit(8byte)
unsigned f3:6; // 70 bit
unsigned :0; // ????? -- 96
unsigned f4:8; //104 -- 13 byte -- 16 byte size
}x;
int main()
{
printf("%d\n",sizeof(x));
}
how to calculate output of this program,please help me,i am just confused with it.
[toc] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-06-18 10:10 -0400 |
| Message-ID | <mluje8$ke4$1@dont-email.me> |
| In reply to | #63510 |
On 06/18/2015 09:45 AM, Rahul Kumar wrote:
> #include <stdio.h>
>
> struct s
> {
> int a:4;
> char b:5;
> int c:7;
> unsigned f1:1;
> unsigned f2:24;
> unsigned :3;
> int :3;// anonymous b.f. -- not accessible
> int :0; // significance -- align to next word boundary -- 47 bit < 64 bit -- align to 64 bit(8byte)
> unsigned f3:6; // 70 bit
> unsigned :0; // ????? -- 96
> unsigned f4:8; //104 -- 13 byte -- 16 byte size
> }x;
>
> int main()
> {
> printf("%d\n",sizeof(x));
> }
>
> how to calculate output of this program,please help me,i am just confused with it.
The only reliable way is to compile and execute it. Different
implementations of C are allowed to give different results for the size.
This is because the C standard allows implementations a lot of freedom
to insert padding bytes in structures, and padding bits in between
bit-fields. There are some restrictions, but no upper limit on the size.
It also depends upon the value of CHAR_BIT, but that's less likely to be
an issue.
--
James Kuyper
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2015-06-18 15:22 +0100 |
| Message-ID | <mluk3u$nk3$1@dont-email.me> |
| In reply to | #63510 |
On 18/06/15 14:45, Rahul Kumar wrote:
> #include <stdio.h>
>
> struct s
> {
> int a:4;
> char b:5;
> int c:7;
> unsigned f1:1;
> unsigned f2:24;
> unsigned :3;
> int :3;// anonymous b.f. -- not accessible
> int :0; // significance -- align to next word boundary -- 47 bit < 64 bit -- align to 64 bit(8byte)
> unsigned f3:6; // 70 bit
> unsigned :0; // ????? -- 96
> unsigned f4:8; //104 -- 13 byte -- 16 byte size
> }x;
>
> int main()
> {
> printf("%d\n",sizeof(x));
> }
>
> how to calculate output of this program,please help me,i am just confused with it.
From N1570 6.7.2.1(5):
A bit-field shall have a type that is a qualified or unqualified version
of _Bool, signed int, unsigned int, or some other implementation-defined
type. It is implementation-defined whether atomic types are permitted.
So char b:5 is only permitted if your implementation specifically
documents the fact in its conformance documentation.
With the exception of char (which is guaranteed to be 1 byte, where a
byte must be *at least* 8 bits wide), the C standard does not specify
byte sizes for types (well, not for vanilla types, anyway, and we're
only concerned with vanilla types here). Therefore, the correct way to
calculate the size of the struct is to use sizeof, which is what you've
done.
The correct way to /print/ size_t values, however, is not %d, but %zd.
(If your compiler doesn't support %zd then it probably doesn't support
anonymous bitfields, either.)
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-06-18 08:07 -0700 |
| Message-ID | <lnbngdjbs0.fsf@nuthaus.mib.org> |
| In reply to | #63514 |
Richard Heathfield <rjh@cpax.org.uk> writes:
[...]
> The correct way to /print/ size_t values, however, is not %d, but %zd.
> (If your compiler doesn't support %zd then it probably doesn't support
> anonymous bitfields, either.)
It's "%zu", since size_t is an unsigned type. "%zd" is likely to work
for reasonable values (it's vanishingly unlikely that the size of this
particular struct would be that big).
If your implementation doesn't support "%zu", you can use "%lu" and cast
the value to unsigned long, which will work as long as the value doesn't
exceed ULONG_MAX.
--
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]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2015-06-18 16:11 +0100 |
| Message-ID | <mlun0i$340$1@dont-email.me> |
| In reply to | #63522 |
On 18/06/15 16:07, Keith Thompson wrote: > Richard Heathfield <rjh@cpax.org.uk> writes: > [...] >> The correct way to /print/ size_t values, however, is not %d, but %zd. >> (If your compiler doesn't support %zd then it probably doesn't support >> anonymous bitfields, either.) > > It's "%zu", since size_t is an unsigned type. What was I thinking? And to save you the trouble, I'll add: s/hat w// -- Richard Heathfield Email: rjh at cpax dot org dot uk "Usenet is a strange place" - dmr 29 July 1999 Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
| From | Ralf Damaschke <rwspam@gmx.de> |
|---|---|
| Date | 2015-06-18 18:48 +0000 |
| Message-ID | <pan.2015.06.18.18.48.09@y2plugh.fqdn.th-h.de> |
| In reply to | #63514 |
Richard Heathfield schrieb: > (If your compiler doesn't support %zd then it probably doesn't support > anonymous bitfields, either.) Here your memory seems to fade. C89 does not have a 'z' length modifier but it already has anonymous bit-fields.
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2015-06-18 23:01 +0100 |
| Message-ID | <mlvf1p$bmp$1@dont-email.me> |
| In reply to | #63547 |
On 18/06/15 19:48, Ralf Damaschke wrote: > Richard Heathfield schrieb: > >> (If your compiler doesn't support %zd then it probably doesn't support >> anonymous bitfields, either.) > > Here your memory seems to fade. C89 does not have a 'z' length modifier but it > already has anonymous bit-fields. You're half-right. You're right that C89 does have anonymous bit-fields, but it wasn't my memory that was fading. Quite simply, I never knew this, ever. But when I went back to C89 to check your outrageous claim, it turned out (outrageously) to be true. Of course, my memory isn't perfect, but on this occasion it was not amnesia that did for me - it was ignorance. -- Richard Heathfield Email: rjh at cpax dot org dot uk "Usenet is a strange place" - dmr 29 July 1999 Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-07-11 08:31 -0700 |
| Message-ID | <kfnr3oeyam1.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #63514 |
Richard Heathfield <rjh@cpax.org.uk> writes: > The correct way to /print/ size_t values, however, is not %d, > but %zd. Isn't this contrary to your rule of limiting yourself to constructs common to C90, C99 and C11? ;)
[toc] | [prev] | [next] | [standalone]
| From | jadill33@gmail.com |
|---|---|
| Date | 2015-07-13 07:51 -0700 |
| Message-ID | <d5db7c37-4b8e-411d-9c7e-c7176e5ad61e@googlegroups.com> |
| In reply to | #65292 |
On Saturday, July 11, 2015 at 11:31:26 AM UTC-4, Tim Rentsch wrote:
> Richard Heathfield <r...@cpax.org.uk> writes:
>
> > The correct way to /print/ size_t values, however, is not %d,
> > but %zd.
>
> Isn't this contrary to your rule of limiting yourself
> to constructs common to C90, C99 and C11? ;)
Yeah, C90 plus <stdint.h>/<inttypes.h> is what I aim for supporting,
to the point of providing my own wrapper if it doesn't exist since I
find it so useful.
Since %zd isn't available on C90 platforms, I resort to making a
format specifier, based on an existing stdint.h file or a wrapper.
\code
/*
* Even if the Microsoft C Runtime library is linked by a C99 supported
* implementation, the printf modifier "z" may still not work.
*/
#if defined(__STDC__) && defined(__STDC_VERSION__)
# if (__STDC__ && __STDC_VERSION__ >= 199901L)
# if defined(_WIN32) || defined(__WIN32__)
/* Microsoft Runtime does not support the 'z' modifier. */
# else
# define inttypes_priusize_defined
# define PRIoSIZE "zo"
# define PRIuSIZE "zu"
# define PRIxSIZE "zx"
# define PRIXSIZE "zX"
# endif
# endif
#endif
#if !defined(inttypes_priusize_defined)
# if (SIZE_MAX == UINT16_MAX)
# define PRIoSIZE PRIo16
# define PRIuSIZE PRIu16
# define PRIxSIZE PRIx16
# define PRIXSIZE PRIX16
# elif (SIZE_MAX == UINT32_MAX)
# define PRIoSIZE PRIo32
# define PRIuSIZE PRIu32
# define PRIxSIZE PRIx32
# define PRIXSIZE PRIX32
# elif !defined(ANSI_C_PSTDINT)
# if defined(UINT64_MAX) && (SIZE_MAX == UINT64_MAX)
# define PRIoSIZE PRIo64
# define PRIuSIZE PRIu64
# define PRIxSIZE PRIx64
# define PRIXSIZE PRIX64
# else
# error "Platform not supported"
# endif
# else
# error "Platform not supported"
# endif
#endif
\endcode
Not a pretty solution, but I've found it useful in my attempt to
stay as close to C90 as I can. And one can add a prefix to PRI
if they don't like the namespace clash.
I'd almost make a case that C99 should have a PRI[ouxX]SIZE in
addition to %zd, but too much water under that bridge. Same for
PTR[di]PTRDIFF and PRI[diouxX]LL.
Best regards,
John D.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-07-15 02:51 -0700 |
| Message-ID | <kfnk2u1u4sw.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #65485 |
jadill33@gmail.com writes:
> On Saturday, July 11, 2015 at 11:31:26 AM UTC-4, Tim Rentsch wrote:
>> Richard Heathfield <r...@cpax.org.uk> writes:
>>
>>> The correct way to /print/ size_t values, however, is not %d,
>>> but %zd.
>>
>> Isn't this contrary to your rule of limiting yourself
>> to constructs common to C90, C99 and C11? ;)
>
> Yeah, C90 plus <stdint.h>/<inttypes.h> is what I aim for supporting,
> to the point of providing my own wrapper if it doesn't exist since I
> find it so useful.
Making your own wrapper sounds like a great approach.
> Since %zd isn't available on C90 platforms, I resort to making a
> format specifier, based on an existing stdint.h file or a wrapper.
Note incidentally that the defined() calls for __STDC__,
UINT64_MAX, and __STDC_VERSION__ are not necessary in the code
you give. Also, strictly speaking SIZE_MAX is not defined in
C90. More on the last point further down.
> \code
> /*
> * Even if the Microsoft C Runtime library is linked by a C99 supported
> * implementation, the printf modifier "z" may still not work.
> */
> #if defined(__STDC__) && defined(__STDC_VERSION__)
> # if (__STDC__ && __STDC_VERSION__ >= 199901L)
> # if defined(_WIN32) || defined(__WIN32__)
> /* Microsoft Runtime does not support the 'z' modifier. */
> # else
> # define inttypes_priusize_defined
> # define PRIoSIZE "zo"
> # define PRIuSIZE "zu"
> # define PRIxSIZE "zx"
> # define PRIXSIZE "zX"
> # endif
> # endif
> #endif
>
> #if !defined(inttypes_priusize_defined)
> # if (SIZE_MAX == UINT16_MAX)
> # define PRIoSIZE PRIo16
> # define PRIuSIZE PRIu16
> # define PRIxSIZE PRIx16
> # define PRIXSIZE PRIX16
> # elif (SIZE_MAX == UINT32_MAX)
> # define PRIoSIZE PRIo32
> # define PRIuSIZE PRIu32
> # define PRIxSIZE PRIx32
> # define PRIXSIZE PRIX32
> # elif !defined(ANSI_C_PSTDINT)
> # if defined(UINT64_MAX) && (SIZE_MAX == UINT64_MAX)
> # define PRIoSIZE PRIo64
> # define PRIuSIZE PRIu64
> # define PRIxSIZE PRIx64
> # define PRIXSIZE PRIX64
> # else
> # error "Platform not supported"
> # endif
> # else
> # error "Platform not supported"
> # endif
> #endif
> \endcode
>
> Not a pretty solution, but I've found it useful in my attempt
> to stay as close to C90 as I can.
I like the idea but I would suggest a slightly different
approach in implementing it (shown below).
> And one can add a prefix to PRI if they don't like the
> namespace clash.
Personally I would favor preserving the PRI_ forms for the
extended names. As a safety measure a, eg, #ifdef PRIuSIZE
could check for potential collisions.
> I'd almost make a case that C99 should have a PRI[ouxX]SIZE in
> addition to %zd, but too much water under that bridge. Same
> for PTR[di]PTRDIFF and PRI[diouxX]LL.
I agree on PTR[di]PTRDIFF. Not sure I see the point for
PRI[diouxX]LL, except maybe for symmetry, in which case maybe
there should be PRI[diouxX]L and PRI[diouxX] as well. You
could add those to your wrapper.
Now here is my suggested alternative for how to do a wrapper.
Note that all I am addressing here is definitions for PRI*SIZE,
not any of the other PRI* names that <inttypes.h> provides,
which I consider a separate topic.
The basic idea is to rely on C99 headers only if running in C99
mode, and apply a heuristic if that is not the case. If SIZE_MAX
is defined, it seems likely that size_t will be the first of
{unsigned, unsigned long, unsigned long long} that matches the
range of size_t. If SIZE_MAX is not available, a simple
heuristic is illustrated in the example; presumably this would
be extended if/when platforms are encountered that need special
casing. To prevent possible mismatches from silently going
wrong, a santity check is put in that functions (no pun intended)
as a "static assert" of sorts.
I tried this out on a couple of different platforms in both C90
and C99, it compiled cleanly (including a test use of PRIuSIZE)
in all cases (and ran correctly showing that the PRIuSIZE use
actually works).
Okay, here we go...
#include <limits.h>
#include <stddef.h>
#if __STDC_VERSION__ > 199900
#include <stdint.h>
#endif
#ifdef SIZE_MAX
# if SIZE_MAX == UINT_MAX
# define SIZE_T_LENGTH_MODIFIER ""
# define SIZE_T_UNDERLYING_TYPE unsigned
# elif SIZE_MAX == ULONG_MAX
# define SIZE_T_LENGTH_MODIFIER "l"
# define SIZE_T_UNDERLYING_TYPE unsigned long
# elif SIZE_MAX == ULLONG_MAX
# define SIZE_T_LENGTH_MODIFIER "ll"
# define SIZE_T_UNDERLYING_TYPE unsigned long long
# else
# error No suitable type found for size_t underlying type.
# endif
#else /* SIZE_MAX is not available, make an educated guess. */
# if UINT_MAX == ULONG_MAX
# define SIZE_T_LENGTH_MODIFIER ""
# define SIZE_T_UNDERLYING_TYPE unsigned
# else
# define SIZE_T_LENGTH_MODIFIER "l"
# define SIZE_T_UNDERLYING_TYPE unsigned long
# endif
#endif
extern int (*size_t_underlying_static_check)( size_t * );
extern int (*size_t_underlying_static_check)( SIZE_T_UNDERLYING_TYPE * );
#define PRIoSIZE SIZE_T_LENGTH_MODIFIER "o"
#define PRIuSIZE SIZE_T_LENGTH_MODIFIER "u"
#define PRIxSIZE SIZE_T_LENGTH_MODIFIER "x"
#define PRIXSIZE SIZE_T_LENGTH_MODIFIER "X"
What do you think?
[toc] | [prev] | [next] | [standalone]
| From | jadill33@gmail.com |
|---|---|
| Date | 2015-07-15 05:55 -0700 |
| Message-ID | <a1a0cdd6-5586-4fe7-8630-ca1b801b2386@googlegroups.com> |
| In reply to | #65608 |
On Wednesday, July 15, 2015 at 5:51:57 AM UTC-4, Tim Rentsch wrote:
> ja...@gmail.com writes:
>
> > On Saturday, July 11, 2015 at 11:31:26 AM UTC-4, Tim Rentsch wrote:
> >> Richard Heathfield <r...@cpax.org.uk> writes:
> >>
> >>> The correct way to /print/ size_t values, however, is not %d,
> >>> but %zd.
> >>
> >> Isn't this contrary to your rule of limiting yourself
> >> to constructs common to C90, C99 and C11? ;)
> >
> > Yeah, C90 plus <stdint.h>/<inttypes.h> is what I aim for supporting,
> > to the point of providing my own wrapper if it doesn't exist since I
> > find it so useful.
>
> Making your own wrapper sounds like a great approach.
>
> > Since %zd isn't available on C90 platforms, I resort to making a
> > format specifier, based on an existing stdint.h file or a wrapper.
>
> Note incidentally that the defined() calls for __STDC__,
> UINT64_MAX, and __STDC_VERSION__ are not necessary in the code
> you give. Also, strictly speaking SIZE_MAX is not defined in
> C90. More on the last point further down.
Ah yes, I forgot to include that about SIZE_MAX in my post. My wrapper
file is quite long (> 1000 lines), and I didn't want my post to go
overboard.
Here is how I approached the definition of SIZE_MAX in my wrapper.
Unfortunately, my wrapper has dependencies defined in a couple of other
headers, but hopefully it's clear what I'm trying to do. Of course,
in C90, this relies on previous definitions of UINTnMAX defined in the
wrapper.
\code
/*
* If SIZE_MAX is not defined, the typical substitute is to use a
* macro defined to something like ((size_t)-1) or (~(size_t)0).
* This definition does not work if one wants to define a fprintf
* modifier macro like PRIuSIZE to print size_t values. Defining
* the set of PRI[ouxX]SIZE modifier macros requires a SIZE_MAX
* definition that is compatible with preprocessor comparisons.
*
* Instead, a different route is needed to define SIZE_MAX. One
* observation is that if one knows the size of 'size_t', one can
* infer what its SIZE_MAX value should be. Unfortunately the
* compiler is not able to evaluate the 'sizeof' operator during
* the preprocessing phase, so one must depend on an external
* indicator of the size of 'size_t'.
*
* One common auto-configuration tool called Autoconf can run a
* test to determine its size that results in a symbol named
* 'SIZEOF_SIZE_T', defined to 'sizeof (size_t)'. That symbol may
* be defined within a Makefile or in a configuration file like
* config.h. If the 'SIZEOF_SIZE_T' symbol is not found, the backup
* plan is to check 'size_t' for compatibility with either 'uint64_t'
* or 'unsigned long', and verify that assertion by checking that
* 'sizeof (size_t) == sizeof (unsigned long)'. If the assertion is
* invalid, the developer will need to resolve the issue manually,
* either by defining the value of 'SIZEOF_SIZE_T' or modifying
* pstdint.h to resolve the conflict.
*/
#if !defined(SIZE_MAX)
# if defined(SIZEOF_SIZE_T) && (CHAR_BIT == 8)
# if (SIZEOF_SIZE_T == 2)
# define SIZE_MAX UINT16_MAX
C_STATIC_ASSERT (sizeof (size_t) == sizeof (uint16_t),
SIZE_MAX_is_compatible_with_uint16_t);
# elif (SIZEOF_SIZE_T == 4)
# define SIZE_MAX UINT32_MAX
C_STATIC_ASSERT (sizeof (size_t) == sizeof (uint32_t),
SIZE_MAX_is_compatible_with_uint32_t);
# elif defined(UINT64_MAX) && (SIZEOF_SIZE_T == 8)
# define SIZE_MAX UINT64_MAX
C_STATIC_ASSERT (sizeof (size_t) == sizeof (uint64_t),
SIZE_MAX_is_compatible_with_uint64_t);
# else
# error "Platform not supported."
# endif
# else
/*
* The C99 standard quotes the following recommended practice.
*
* 7.17 Common definitions <stddef.h>
*
* 4 The types used for size_t and ptrdiff_t should not
* have an integer conversion rank greater than that of
* signed long int unless the implementation supports
* objects large enough to make this necessary.
*
* If this assertion is not valid, then one must manually
* define 'SIZEOF_SIZE_T'.
*
* On 64-bit Microsoft platforms, the constant ULONG_MAX will
* not work because unsigned long is 32-bits while size_t is
* 64-bits.
*/
# if defined(_WIN64)
define SIZE_MAX UINT64_MAX
C_STATIC_ASSERT (sizeof (size_t) == sizeof (uint64_t),
SIZE_MAX_is_compatible_with_uint64_t);
# else
# define SIZE_MAX ULONG_MAX
C_STATIC_ASSERT (sizeof (size_t) == sizeof (unsigned long),
SIZE_MAX_is_compatible_with_unsigned_long);
# endif
# endif
#endif
\endcode
> > \code
> > /*
> > * Even if the Microsoft C Runtime library is linked by a C99 supported
> > * implementation, the printf modifier "z" may still not work.
> > */
> > #if defined(__STDC__) && defined(__STDC_VERSION__)
> > # if (__STDC__ && __STDC_VERSION__ >= 199901L)
> > # if defined(_WIN32) || defined(__WIN32__)
> > /* Microsoft Runtime does not support the 'z' modifier. */
> > # else
> > # define inttypes_priusize_defined
> > # define PRIoSIZE "zo"
> > # define PRIuSIZE "zu"
> > # define PRIxSIZE "zx"
> > # define PRIXSIZE "zX"
> > # endif
> > # endif
> > #endif
> >
> > #if !defined(inttypes_priusize_defined)
> > # if (SIZE_MAX == UINT16_MAX)
> > # define PRIoSIZE PRIo16
> > # define PRIuSIZE PRIu16
> > # define PRIxSIZE PRIx16
> > # define PRIXSIZE PRIX16
> > # elif (SIZE_MAX == UINT32_MAX)
> > # define PRIoSIZE PRIo32
> > # define PRIuSIZE PRIu32
> > # define PRIxSIZE PRIx32
> > # define PRIXSIZE PRIX32
> > # elif !defined(ANSI_C_PSTDINT)
> > # if defined(UINT64_MAX) && (SIZE_MAX == UINT64_MAX)
> > # define PRIoSIZE PRIo64
> > # define PRIuSIZE PRIu64
> > # define PRIxSIZE PRIx64
> > # define PRIXSIZE PRIX64
> > # else
> > # error "Platform not supported"
> > # endif
> > # else
> > # error "Platform not supported"
> > # endif
> > #endif
> > \endcode
> >
> > Not a pretty solution, but I've found it useful in my attempt
> > to stay as close to C90 as I can.
>
> I like the idea but I would suggest a slightly different
> approach in implementing it (shown below).
>
> > And one can add a prefix to PRI if they don't like the
> > namespace clash.
>
> Personally I would favor preserving the PRI_ forms for the
> extended names. As a safety measure a, eg, #ifdef PRIuSIZE
> could check for potential collisions.
I agree.
> > I'd almost make a case that C99 should have a PRI[ouxX]SIZE in
> > addition to %zd, but too much water under that bridge. Same
> > for PTR[di]PTRDIFF and PRI[diouxX]LL.
>
> I agree on PTR[di]PTRDIFF. Not sure I see the point for
> PRI[diouxX]LL, except maybe for symmetry, in which case maybe
> there should be PRI[diouxX]L and PRI[diouxX] as well. You
> could add those to your wrapper.
The motivation for most of these definitions was dealing with Microsoft's
C Runtime (especially when it didn't support C99 printf modifiers). To
support C99 long long, I felt PRI[diouxX]LL was a method I could portably
print 64-bit integers using either the C99 "ll" or the Microsoft "I64"
definitions. Since C90 supports fprintf modifiers for the long and int
types, I did not see a motivation to add PRI[diouxX]L or PRI[diouxX] as
extensions.
> Now here is my suggested alternative for how to do a wrapper.
> Note that all I am addressing here is definitions for PRI*SIZE,
> not any of the other PRI* names that <inttypes.h> provides,
> which I consider a separate topic.
>
> The basic idea is to rely on C99 headers only if running in C99
> mode, and apply a heuristic if that is not the case. If SIZE_MAX
> is defined, it seems likely that size_t will be the first of
> {unsigned, unsigned long, unsigned long long} that matches the
> range of size_t. If SIZE_MAX is not available, a simple
> heuristic is illustrated in the example; presumably this would
> be extended if/when platforms are encountered that need special
> casing. To prevent possible mismatches from silently going
> wrong, a santity check is put in that functions (no pun intended)
> as a "static assert" of sorts.
>
> I tried this out on a couple of different platforms in both C90
> and C99, it compiled cleanly (including a test use of PRIuSIZE)
> in all cases (and ran correctly showing that the PRIuSIZE use
> actually works).
>
> Okay, here we go...
>
>
> #include <limits.h>
> #include <stddef.h>
> #if __STDC_VERSION__ > 199900
> #include <stdint.h>
> #endif
>
> #ifdef SIZE_MAX
>
> # if SIZE_MAX == UINT_MAX
> # define SIZE_T_LENGTH_MODIFIER ""
> # define SIZE_T_UNDERLYING_TYPE unsigned
> # elif SIZE_MAX == ULONG_MAX
> # define SIZE_T_LENGTH_MODIFIER "l"
> # define SIZE_T_UNDERLYING_TYPE unsigned long
> # elif SIZE_MAX == ULLONG_MAX
> # define SIZE_T_LENGTH_MODIFIER "ll"
> # define SIZE_T_UNDERLYING_TYPE unsigned long long
> # else
> # error No suitable type found for size_t underlying type.
> # endif
>
> #else /* SIZE_MAX is not available, make an educated guess. */
>
> # if UINT_MAX == ULONG_MAX
> # define SIZE_T_LENGTH_MODIFIER ""
> # define SIZE_T_UNDERLYING_TYPE unsigned
> # else
> # define SIZE_T_LENGTH_MODIFIER "l"
> # define SIZE_T_UNDERLYING_TYPE unsigned long
> # endif
>
> #endif
>
> extern int (*size_t_underlying_static_check)( size_t * );
> extern int (*size_t_underlying_static_check)( SIZE_T_UNDERLYING_TYPE * );
>
> #define PRIoSIZE SIZE_T_LENGTH_MODIFIER "o"
> #define PRIuSIZE SIZE_T_LENGTH_MODIFIER "u"
> #define PRIxSIZE SIZE_T_LENGTH_MODIFIER "x"
> #define PRIXSIZE SIZE_T_LENGTH_MODIFIER "X"
>
>
> What do you think?
I like the idea, and it would shorten my file by a bit. I'm not quite
sure what's going on with the 'underlying_static_check', so can you
explain that in a little more detail?
Thanks again for your time.
Best regards,
John D.
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-07-20 10:01 -0700 |
| Message-ID | <kfnk2tun4oz.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #65619 |
jadill33@gmail.com writes: > On Wednesday, July 15, 2015 at 5:51:57 AM UTC-4, Tim Rentsch wrote: >> ja...@gmail.com writes: >> >> [snipped rather ruthlessly] >> >> Note incidentally that the defined() calls for __STDC__, >> UINT64_MAX, and __STDC_VERSION__ are not necessary in the code >> you give. Also, strictly speaking SIZE_MAX is not defined in >> C90. More on the last point further down. > > Ah yes, I forgot to include that about SIZE_MAX in my post. My wrapper > file is quite long (> 1000 lines), and I didn't want my post to go > overboard. > > Here is how I approached the definition of SIZE_MAX in my wrapper. > [snip] Okay, glad to see you considered it. >>> I'd almost make a case that C99 should have a PRI[ouxX]SIZE in >>> addition to %zd, but too much water under that bridge. Same >>> for PTR[di]PTRDIFF and PRI[diouxX]LL. >> >> I agree on PTR[di]PTRDIFF. Not sure I see the point for >> PRI[diouxX]LL, except maybe for symmetry, in which case maybe >> there should be PRI[diouxX]L and PRI[diouxX] as well. You >> could add those to your wrapper. > > The motivation for most of these definitions was dealing with > Microsoft's C Runtime (especially when it didn't support C99 > printf modifiers). [snip] Ahh, now I get it. Very sensible. >> Now here is my suggested alternative for how to do a wrapper. >> [snip] >> >> #ifdef SIZE_MAX >> >> # if SIZE_MAX == UINT_MAX >> # define SIZE_T_LENGTH_MODIFIER "" >> # define SIZE_T_UNDERLYING_TYPE unsigned >> # elif SIZE_MAX == ULONG_MAX >> # define SIZE_T_LENGTH_MODIFIER "l" >> # define SIZE_T_UNDERLYING_TYPE unsigned long >> # elif SIZE_MAX == ULLONG_MAX >> # define SIZE_T_LENGTH_MODIFIER "ll" >> # define SIZE_T_UNDERLYING_TYPE unsigned long long >> # else >> # error No suitable type found for size_t underlying type. >> # endif >> >> #else /* SIZE_MAX is not available, make an educated guess. */ >> [snip] >> #endif >> >> extern int (*size_t_underlying_static_check)( size_t * ); >> extern int (*size_t_underlying_static_check)( SIZE_T_UNDERLYING_TYPE * ); > > I like the idea, and it would shorten my file by a bit. I'm not quite > sure what's going on with the 'underlying_static_check', so can you > explain that in a little more detail? Simple idea. By declaring the function twice, once with 'size_t *' and once with 'SIZE_T_UNDERLYING_TYPE *', which of course will expand to one of 'unsigned *', etc, the two declarations will be checked for type compatibility. Doing this ensures the type we guessed for size_t matches the actual type that size_t corresponds to, since otherwise the type mismatch will produce a diagnostic (and probably a fatal one, although of course there are no guarantees about that).
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2015-07-13 22:07 +0100 |
| Message-ID | <mo197q$al6$1@dont-email.me> |
| In reply to | #65292 |
On 11/07/15 16:31, Tim Rentsch wrote: > Richard Heathfield <rjh@cpax.org.uk> writes: > >> The correct way to /print/ size_t values, however, is not %d, >> but %zd. > > Isn't this contrary to your rule of limiting yourself > to constructs common to C90, C99 and C11? ;) My answer was posited on the basis that the code was C99 (because of anonymous wossnames, which I incorrectly thought were not supported by C90). In writing what I would consider to be maximally portable code, I would not use %z at all. But, if (as I incorrectly thought) one is using C99 anyway, one might as well take advantage of %z. -- Richard Heathfield Email: rjh at cpax dot org dot uk "Usenet is a strange place" - dmr 29 July 1999 Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-07-13 14:16 -0700 |
| Message-ID | <lnmvyzlpvf.fsf@kst-u.example.com> |
| In reply to | #65522 |
Richard Heathfield <rjh@cpax.org.uk> writes:
> On 11/07/15 16:31, Tim Rentsch wrote:
>> Richard Heathfield <rjh@cpax.org.uk> writes:
>>
>>> The correct way to /print/ size_t values, however, is not %d,
>>> but %zd.
>>
>> Isn't this contrary to your rule of limiting yourself
>> to constructs common to C90, C99 and C11? ;)
>
>
> My answer was posited on the basis that the code was C99 (because of
> anonymous wossnames, which I incorrectly thought were not supported by
> C90). In writing what I would consider to be maximally portable code, I
> would not use %z at all. But, if (as I incorrectly thought) one is using
> C99 anyway, one might as well take advantage of %z.
I mentioned this before, but the correct format for size_t is "%zu", not
"%zd" (since size_t is an unsigned type).
--
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]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-07-15 02:11 -0700 |
| Message-ID | <kfnoajdu6na.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #65522 |
Richard Heathfield <rjh@cpax.org.uk> writes: > On 11/07/15 16:31, Tim Rentsch wrote: >> Richard Heathfield <rjh@cpax.org.uk> writes: >> >>> The correct way to /print/ size_t values, however, is not %d, >>> but %zd. >> >> Isn't this contrary to your rule of limiting yourself >> to constructs common to C90, C99 and C11? ;) > > My answer was posited on the basis that the code was C99 (because of > anonymous wossnames, which I incorrectly thought were not supported by > C90). In writing what I would consider to be maximally portable code, > I would not use %z at all. But, if (as I incorrectly thought) one is > using C99 anyway, one might as well take advantage of %z. Yes, I see that, and it's quite reasonable. I was gently (I hoped) making fun of your position on which parts of C should be used, which seems to me more uncompromising than it should be. Probably I shouldn't have - sorry about that.
[toc] | [prev] | [next] | [standalone]
| From | Richard Heathfield <rjh@cpax.org.uk> |
|---|---|
| Date | 2015-07-15 10:58 +0100 |
| Message-ID | <mo5apb$1le$1@dont-email.me> |
| In reply to | #65607 |
On 15/07/15 10:11, Tim Rentsch wrote: > Richard Heathfield <rjh@cpax.org.uk> writes: > >> On 11/07/15 16:31, Tim Rentsch wrote: >>> Richard Heathfield <rjh@cpax.org.uk> writes: >>> >>>> The correct way to /print/ size_t values, however, is not %d, >>>> but %zd. [Aside: that should, of course, be %zu.] >>> >>> Isn't this contrary to your rule of limiting yourself >>> to constructs common to C90, C99 and C11? ;) >> >> My answer was posited on the basis that the code was C99 (because of >> anonymous wossnames, which I incorrectly thought were not supported by >> C90). In writing what I would consider to be maximally portable code, >> I would not use %z at all. But, if (as I incorrectly thought) one is >> using C99 anyway, one might as well take advantage of %z. > > Yes, I see that, and it's quite reasonable. I was gently > (I hoped) making fun of your position on which parts of > C should be used, which seems to me more uncompromising > than it should be. Probably I shouldn't have - sorry > about that. For the avoidance of doubt, my uncompromising position relates to which parts of C *I* should use. I do not insist that the world follows my lead (although it is most welcome so to do if it chooses). When people ask about maximally[1] portable solutions, naturally I throw my tuppence into the ring, but there are times (albeit not all that many of them) when I will take off my zealot hat and chip in to a C99- or C11-specific thread. As for the gentle teasing, I don't mind that at all, and no apology is necessary. Them as dishes it out ought to be able to take it, and I certainly dish it out on occasion. [1] well, *almost* maximally. Freestanding implementations are a kettle of a different colour. -- Richard Heathfield Email: rjh at cpax dot org dot uk "Usenet is a strange place" - dmr 29 July 1999 Sig line 4 vacant - apply within
[toc] | [prev] | [next] | [standalone]
| From | Tim Rentsch <txr@alumni.caltech.edu> |
|---|---|
| Date | 2015-07-20 10:05 -0700 |
| Message-ID | <kfnfv4in4jd.fsf@x-alumni2.alumni.caltech.edu> |
| In reply to | #65610 |
Richard Heathfield <rjh@cpax.org.uk> writes: > On 15/07/15 10:11, Tim Rentsch wrote: >> Richard Heathfield <rjh@cpax.org.uk> writes: >> >>> On 11/07/15 16:31, Tim Rentsch wrote: >>>> Richard Heathfield <rjh@cpax.org.uk> writes: >>>> >>>>> The correct way to /print/ size_t values, however, is not %d, >>>>> but %zd. > > [Aside: that should, of course, be %zu.] > >>>> Isn't this contrary to your rule of limiting yourself >>>> to constructs common to C90, C99 and C11? ;) >>> >>> My answer was posited on the basis that the code was C99 (because of >>> anonymous wossnames, which I incorrectly thought were not supported by >>> C90). In writing what I would consider to be maximally portable code, >>> I would not use %z at all. But, if (as I incorrectly thought) one is >>> using C99 anyway, one might as well take advantage of %z. >> >> Yes, I see that, and it's quite reasonable. I was gently >> (I hoped) making fun of your position on which parts of >> C should be used, which seems to me more uncompromising >> than it should be. Probably I shouldn't have - sorry >> about that. > > [snip] > > As for the gentle teasing, I don't mind that at all, and no apology is > necessary. [snip] I appreciate you taking it in good spirits. Despite that, I believe that it was not appropriate to indulge the impulse, and will try to refrain from indulging similar impulses in the future.
[toc] | [prev] | [next] | [standalone]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-06-18 12:26 -0400 |
| Message-ID | <5582F12D.3070708@verizon.net> |
| In reply to | #63510 |
On 06/18/2015 09:45 AM, Rahul Kumar wrote:
> #include <stdio.h>
>
> struct s
> {
> int a:4;
> char b:5;
> int c:7;
> unsigned f1:1;
> unsigned f2:24;
> unsigned :3;
> int :3;// anonymous b.f. -- not accessible
> int :0; // significance -- align to next word boundary -- 47 bit < 64 bit -- align to 64 bit(8byte)
> unsigned f3:6; // 70 bit
> unsigned :0; // ????? -- 96
> unsigned f4:8; //104 -- 13 byte -- 16 byte size
> }x;
>
> int main()
> {
> printf("%d\n",sizeof(x));
> }
>
> how to calculate output of this program,please help me,i am just confused with it.
My first answer was correct, but not particularly detailed. I'll give
you some more details this time.
As Richard has already mentioned, a compiler is not required to accept a
bit-field of type 'char', so this code can only be ported to compilers
that accept that type.
A bit-field width is not allowed to exceed the size in bits of the
corresponding type. Therefore, the declaration of f2 is allowed only on
implementations where "unsigned int" has at least 24 bits.
It is implementation-defined whether a bit-field of type 'int' has a
signed or unsigned type. Since it's almost never a good idea to be
unsure whether a type is signed or unsigned, I recommend replacing "int"
with "signed int" (or, more simply, "signed") in all of the above member
declarations. The same is probably true for any implementation that
allows bit-fields of "char" type. I recommend explicitly declaring "b"
as either "signed char" or "unsigned char", depending upon what you
actually want it to be.
"There may be unnamed padding within a structure object, but not at its
beginning." (6.7.2.1p15). Note that there is no upper limit on the
amount of padding. This is the key thing that makes it impossible to
"calculate" the size of this struct.
In practice, most implementations will align a struct with the strictest
alignment of any of it's members, and align each individual member
according to the alignment requirements of it's type. They will
introduce padding between members only as needed to ensure correct
alignment. The size of a struct must be a multiple of alignment
requirement for the struct, and most implementations will put padding at
the end of a struct only if needed for that purpose. However, you
shouldn't write code that relies upon these things.
If you're using C2011, you can use _Alignof(type) to find out the
alignment requirements for a type, and you can use _Alignas() to impose
stricter alignment requirements on an object than would otherwise apply.
In older versions of C, the only way to find out about such things was
to read the documentation for the compiler.
6.7.2.1p11 says:
> An implementation may allocate any addressable storage unit large enough to hold a bitfield.
> If enough space remains, a bit-field that immediately follows another bit-field in a
> structure shall be packed into adjacent bits of the same unit. If insufficient space remains,
> whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is
> implementation-defined. The order of allocation of bit-fields within a unit (high-order to
> low-order or low-order to high-order) is implementation-defined. The alignment of the
> addressable storage unit is unspecified.
Note that this implies that padding bytes are not permitted between
addressable storage units (ASU). If there's enough space to put the next
bit-field in the same ASU as the previous one, it must be put there. If
there isn't enough room, the implementation has a choice, but only
between two options: a) putting part of the bit-field in the same ASU,
and the rest of it in the next one or b) putting it entirely in the next
ASU. Either way, there's no room for padding bytes between the ASUs.
There might be more than CHAR_BIT consecutive padding bits within an
ASU, but only if the next struct member is not a bit-field small enough
to fit in the available bits.
Because the implementation does get to make that choice, and also
because it gets to choose the size and alignment requirements of the
ASU, there's still considerable freedom for different implementations to
give different sizes to the same struct, even if every member is
bit-field, even though that means that padding bytes between members are
not allowed.
Finally, even if the size of the struct in bits were completely
specified, the value returned by "sizeof x" would depend upon the value
of CHAR_BIT from <limits.h>.
The comments in the struct imply that it was written by someone who
knows about 6.7.2.1p12 - but if it wasn't written by you, you might need
to know this in order to understand what they wrote:
"A bit-field declaration with no declarator, but only a colon and a
width, indicates an unnamed bit-field. As a special case, a bit-field
structure member with a width of 0 indicates that no further bit-field
is to be packed into the unit in which the previous bitfield,
if any, was placed."
Lets examine one of the possibilities. Assume that the ASU has a size
and alignment requirement of 16, and that bit fields which don't fit
always are allocated to the next ASU. Then:
The first ASU will contain a(4 bits) b(5 bits) and c(7 bits). The order
of these fields within the ASU is unspecified.
The next ASU will contain only f1.
f2(24 bits) will be split between the third and fourth ASUs, followed by
the two unnamed bit-fields (3 bits each). How much of f2 will be placed
in the first ASU is unspecified - it could be as little as 14 bits, or
as much as 16 bits. Having two consecutive unnamed bit-fields seems odd
to me. It's not entirely pointless - whether those fields will be split
up or put in the same ASU will depend upon the size of the ASU.
f3(6 bits) will be put in the fifth ASU, and because of the bit-field
with a length of 0, f4(8 bits) will have to be put in the sixth
bit-field, for a total size of 6 ASUs * 16 bits/ASU = 96 bits. If
CHAR_BIT == 8, then sizeof(x) will be 12.
Note that this layout is inconsistent with the comments in the code. I
suspect that those comments were based upon the assumption that the ASU
had a size of 32 bits, rather than 16, neatly demonstrating why there's
no single answer to your question.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-06-18 10:14 -0700 |
| Message-ID | <ln7fr1j5vr.fsf@nuthaus.mib.org> |
| In reply to | #63530 |
James Kuyper <jameskuyper@verizon.net> writes:
> On 06/18/2015 09:45 AM, Rahul Kumar wrote:
>> #include <stdio.h>
>>
>> struct s
>> {
>> int a:4;
>> char b:5;
>> int c:7;
>> unsigned f1:1;
>> unsigned f2:24;
>> unsigned :3;
>> int :3;// anonymous b.f. -- not accessible
>> int :0; // significance -- align to next word boundary -- 47 bit < 64 bit -- align to 64 bit(8byte)
>> unsigned f3:6; // 70 bit
>> unsigned :0; // ????? -- 96
>> unsigned f4:8; //104 -- 13 byte -- 16 byte size
>> }x;
>>
>> int main()
>> {
>> printf("%d\n",sizeof(x));
>> }
>>
>> how to calculate output of this program,please help me,i am just confused with it.
>
> My first answer was correct, but not particularly detailed. I'll give
> you some more details this time.
>
> As Richard has already mentioned, a compiler is not required to accept a
> bit-field of type 'char', so this code can only be ported to compilers
> that accept that type.
> A bit-field width is not allowed to exceed the size in bits of the
> corresponding type. Therefore, the declaration of f2 is allowed only on
> implementations where "unsigned int" has at least 24 bits.
Another complication: the type of a bit field can the layout of the
containing structure, even for bit fields of the same size. Some
ABIs require this, though there's no hint of it in the C standard.
For example, on my system this program:
#include <stdio.h>
int main(void) {
struct s1 { unsigned char bf:1; };
struct s2 { unsigned short bf:1; };
struct s3 { unsigned int bf:1; };
struct s4 { unsigned long bf:1; };
struct s5 { unsigned long long bf:1; };
printf("%zu %zu %zu %zu %zu\n",
sizeof (struct s1),
sizeof (struct s2),
sizeof (struct s3),
sizeof (struct s4),
sizeof (struct s5));
}
produces this output:
1 2 4 8 8
Of course the output, and even the legality of the program itself, are
implementation-defined, and the actual output is within the bounds of
what the standard permits.
> It is implementation-defined whether a bit-field of type 'int' has a
> signed or unsigned type. Since it's almost never a good idea to be
> unsure whether a type is signed or unsigned, I recommend replacing "int"
> with "signed int" (or, more simply, "signed") in all of the above member
> declarations. The same is probably true for any implementation that
> allows bit-fields of "char" type. I recommend explicitly declaring "b"
> as either "signed char" or "unsigned char", depending upon what you
> actually want it to be.
It probably doesn't matter whether an anonymous bit field is signed
or unsigned, but yes, specifying `unsigned int` or `signed int`
rather than just `int` is a good habit. Most bit fields should
probably be unsigned, but it depends on what they're used for.
[...]
--
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] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web