[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c

int vs. unsigned int vs. size_t

Steve Keller

4/30/2011 6:41:00 AM

This is a style question. To iterate through an array I often use
code similar to the following:

#define ASIZE(a) (sizeof(a) / sizeof((a)[0])
int a[] = { ... };

void foo(void)
{
int i;
for (i = 0; i < ASIZE(a); i++)
/* do something with a[i]. */
}

With all warnings enabled, gcc will warn about a comparison between
signed and unsigned integer types, because sizeof() yields a size_t
which is unsigned. To eliminate that warning I could use unsigned int
or size_t for the variable i. But IMO int feels most natural and
size_t might have unwanted overhead, if it is a large integer type and
I know that the array size will be very small (i.e. less than INT_MAX
elements).

So, what type for i do you prefer in cases like this?

--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
32 Answers

Ike Naar

4/30/2011 7:39:00 AM

0

On 2011-04-30, Steve Keller <keller@no.invalid> wrote:
> This is a style question. To iterate through an array I often use
> code similar to the following:
>
> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
> int a[] = { ... };
>
> void foo(void)
> {
> int i;
> for (i = 0; i < ASIZE(a); i++)
> /* do something with a[i]. */
> }
>
> With all warnings enabled, gcc will warn about a comparison between
> signed and unsigned integer types, because sizeof() yields a size_t
> which is unsigned. To eliminate that warning I could use unsigned int
> or size_t for the variable i. But IMO int feels most natural and
> size_t might have unwanted overhead, if it is a large integer type and
> I know that the array size will be very small (i.e. less than INT_MAX
> elements).
> So, what type for i do you prefer in cases like this?

size_t, probably.
Why would size_t have more overhead than int?
It could be the other way around! Did you measure?

If you're into micro-optimizations, perhaps you also want to explore
``++i'' vs. ``i++'', or ``i != ASIZE(a)'' vs. ``i < ASIZE(a)''.

But it might be more productive (if you need to improve the speed
of the program at all) to check if a few calls to foo() can be eliminated,
or focus on the ``/* do something with a[i]. */'' part.

Eric Sosman

4/30/2011 11:30:00 AM

0

On 4/30/2011 2:40 AM, Steve Keller wrote:
> This is a style question. To iterate through an array I often use
> code similar to the following:
>
> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
> int a[] = { ... };
>
> void foo(void)
> {
> int i;
> for (i = 0; i< ASIZE(a); i++)
> /* do something with a[i]. */
> }
>
> With all warnings enabled, gcc will warn about a comparison between
> signed and unsigned integer types, because sizeof() yields a size_t
> which is unsigned. To eliminate that warning I could use unsigned int
> or size_t for the variable i. But IMO int feels most natural and
> size_t might have unwanted overhead, if it is a large integer type and
> I know that the array size will be very small (i.e. less than INT_MAX
> elements).
>
> So, what type for i do you prefer in cases like this?

The "overhead" of size_t in this use is probably too small to
measure without effort too large to make sense. In fact, there's
a plausible argument that the "overhead" could even be negative:
Suppose `i' is narrower, and there's extra code to promote it for
every comparison to `ASIZE(a)'. It's not as if you were storing
umpty gazillion size_t values and trying to save space: One variable
and one constant, and that's peanuts.

But if you insist on using a type that might (*might*) be
narrower, unsigned int will placate gcc. The only drawback of
using an unsigned index type (including size_t) is that there's
no way to stop a loop by going negative when stepping backwards,
so you've got to pay close attention to your idioms:

// Doesn't work:
for (unsigned int i = N; --i >= 0; ) { ... }

// Works:
for (unsigned int i = N; i-- > 0; ) { ... }

The latter is sure to arouse suspicion among micro-optimizers,
because half-understood rumors about the relative efficiency of
pre- and post-{in,de}crement operators lurk like shadows in their
brains' dusty and vacant attics. To them -- and to you, with your
worries about the "overhead" of size_t -- I offer Jackson's Laws:

First Law of Program Optimization:
Don't do it.

Second Law of Program Optimization (for experts only):
Don't do it yet.

--
Eric Sosman
esosman@ieee-dot-org.invalid

ralph

4/30/2011 12:51:00 PM

0

On Sat, 30 Apr 2011 07:30:28 -0400, Eric Sosman
<esosman@ieee-dot-org.invalid> wrote:

> ... To them -- and to you, with your
>worries about the "overhead" of size_t -- I offer Jackson's Laws:
>
> First Law of Program Optimization:
> Don't do it.
>
> Second Law of Program Optimization (for experts only):
> Don't do it yet.

I agree.

Curious. How did it get the name "Jackson's Laws"?

-ralph

Azazel

4/30/2011 2:57:00 PM

0

On 2011-04-30, ralph <nt_consulting64@yahoo.net> wrote:
> On Sat, 30 Apr 2011 07:30:28 -0400, Eric Sosman
> <esosman@ieee-dot-org.invalid> wrote:
>
> > ... To them -- and to you, with
> your
> >worries about the "overhead" of size_t -- I offer Jackson's Laws:
> >
> > First Law of Program Optimization:
> > Don't do it.
> >
> > Second Law of Program Optimization (for experts only):
> > Don't do it yet.
>
> I agree.
>
> Curious. How did it get the name "Jackson's Laws"?

http://en.wikipedia.org/wiki/Program_optimizat...

--
Az.

Tim Prince

4/30/2011 4:27:00 PM

0

On 4/29/2011 11:40 PM, Steve Keller wrote:
> This is a style question. To iterate through an array I often use
> code similar to the following:
>
> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
> int a[] = { ... };
>
> void foo(void)
> {
> int i;
> for (i = 0; i< ASIZE(a); i++)
> /* do something with a[i]. */
> }
>
> With all warnings enabled, gcc will warn about a comparison between
> signed and unsigned integer types, because sizeof() yields a size_t
> which is unsigned. To eliminate that warning I could use unsigned int
> or size_t for the variable i. But IMO int feels most natural and
> size_t might have unwanted overhead, if it is a large integer type and
> I know that the array size will be very small (i.e. less than INT_MAX
> elements).
>
> So, what type for i do you prefer in cases like this?
>
How about defining a loop invariant for the loop test, with matching
data type?
int i, ilimit=ASIZE(a);
for (i = 0; i< ilimit; i++)

If your compiler performs optimizations based on countability of the for
loop, this avoids uncertainty there too.

--
Tim Prince

ram

4/30/2011 5:25:00 PM

0

Tim Prince <tprince@computer.org> writes:
>How about defining a loop invariant for the loop test, with matching
>data type?
> int i, ilimit=ASIZE(a);
> for (i = 0; i< ilimit; i++)

An invariant »ilimit«

size_t ilimit = ASIZE(a);

can be made more readable as

size_t const ilimit = ASIZE(a);

.


pozz

4/30/2011 5:34:00 PM

0

Il 30/04/2011 08:40, Steve Keller ha scritto:
> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
> int a[] = { ... };
>
> void foo(void)
> {
> int i;
> for (i = 0; i< ASIZE(a); i++)
> /* do something with a[i]. */
> }

I'm reading "C Unleashed" book and I found in some listings the
following code:

#define ASIZE(a) (sizeof(a) / sizeof((a)[0])
int a[] = { ... };

void foo(void)
{
int i;
for (i = 0; i < (int) ASIZE(a); i++)
/* do something with a[i]. */
}

Tim Prince

4/30/2011 7:56:00 PM

0

On 4/30/2011 10:24 AM, Stefan Ram wrote:
> Tim Prince<tprince@computer.org> writes:
>> How about defining a loop invariant for the loop test, with matching
>> data type?
>> int i, ilimit=ASIZE(a);
>> for (i = 0; i< ilimit; i++)
>
> An invariant »ilimit«
>
> size_t ilimit = ASIZE(a);
>
> can be made more readable as
>
> size_t const ilimit = ASIZE(a);
>
> .
>
>
const yes, size_t no, the point is to avoid any implied up-casting
inside the loop.

--
Tim Prince

Ian Collins

4/30/2011 9:03:00 PM

0

On 05/ 1/11 05:33 AM, pozz wrote:
> Il 30/04/2011 08:40, Steve Keller ha scritto:
>> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
>> int a[] = { ... };
>>
>> void foo(void)
>> {
>> int i;
>> for (i = 0; i< ASIZE(a); i++)
>> /* do something with a[i]. */
>> }
>
> I'm reading "C Unleashed" book and I found in some listings the
> following code:
>
> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
> int a[] = { ... };
>
> void foo(void)
> {
> int i;
> for (i = 0; i< (int) ASIZE(a); i++)
> /* do something with a[i]. */
> }

That's pretty gross. If they are going to use an invariant of one type,
they should use a counter of the same type and not an ugly, pointless
and distracting cast.

--
Ian Collins

Tim Prince

4/30/2011 9:34:00 PM

0

On 4/30/2011 2:03 PM, Ian Collins wrote:
> On 05/ 1/11 05:33 AM, pozz wrote:
>> Il 30/04/2011 08:40, Steve Keller ha scritto:
>>> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
>>> int a[] = { ... };
>>>
>>> void foo(void)
>>> {
>>> int i;
>>> for (i = 0; i< ASIZE(a); i++)
>>> /* do something with a[i]. */
>>> }
>>
>> I'm reading "C Unleashed" book and I found in some listings the
>> following code:
>>
>> #define ASIZE(a) (sizeof(a) / sizeof((a)[0])
>> int a[] = { ... };
>>
>> void foo(void)
>> {
>> int i;
>> for (i = 0; i< (int) ASIZE(a); i++)
>> /* do something with a[i]. */
>> }
>
> That's pretty gross. If they are going to use an invariant of one type,
> they should use a counter of the same type and not an ugly, pointless
> and distracting cast.
>
The code evidently supported only INT_MAX sized arrays. If there were
any possibility of larger than that (certainly not far fetched
nowadays), this ASIZE macro could have been asserted <= INT_MAX ahead of
the loop. size_t is not necessarily a good choice for a loop counter;
the largest signed int type no larger than size_t might be useful.

--
Tim Prince