What type is array indices converted to?

M

magnus.ahman

I malloc() memory and use the pointer in indexing - ptr[index] - where
index is a size_t, but I get this warning from lint: unsigned long
converted to long. Obviuosly size_t is unsigned long on my system, but
what is the signed long - ptr_diff or what?

I've read on the web that size_t is safe to index any array. So is
this
warning from lint just bullsh-t or should I be worried that my code
will
break when it uses a lot of memory?
 
U

user923005

I malloc() memory and use the pointer in indexing - ptr[index] - where
index is a size_t, but I get this warning from lint: unsigned long
converted to long. Obviuosly size_t is unsigned long on my system, but
what is the signed long - ptr_diff or what?

I've read on the web that size_t is safe to index any array. So is
this
warning from lint just bullsh-t or should I be worried that my code
will
break when it uses a lot of memory?

Show us the actual code that gets the error.
 
K

Keith Thompson

I malloc() memory and use the pointer in indexing - ptr[index] - where
index is a size_t, but I get this warning from lint: unsigned long
converted to long. Obviuosly size_t is unsigned long on my system, but
what is the signed long - ptr_diff or what?

I've read on the web that size_t is safe to index any array. So is
this warning from lint just bullsh-t or should I be worried that my
code will break when it uses a lot of memory?

An array index can have any integer type, signed or unsigned; it's not
converted to anything.
 
M

magnus.ahman

Let's see the code.

$ cat test.c
#include <stddef.h>
#include <stdlib.h>

void append(short);

short *buf;
size_t bufSize;

int main(void) {
if ((buf = malloc(bufSize = (size_t) 1)) == NULL) exit(1); /* out of
memory */
*buf = 6;
append(28);
append(496);
free(buf);
return 0;
}

void append(short element) {
short *newBuf;

if ((size_t) -1 - (size_t) 1 < bufSize) exit(1); /* can't address
more */
if ((newBuf = realloc(buf, ++bufSize)) == NULL) {
free(buf);
exit(1); /* out of memory */
}
buf = newBuf;
buf[bufSize - (size_t) 1] = element; /* line 27 */
}
$ lint test.c
test.c:27: warning: converted from 'unsigned long' to 'long'
Lint pass2:
 
R

Richard Tobin

buf[bufSize - (size_t) 1] = element; /* line 27 */
$ lint test.c
test.c:27: warning: converted from 'unsigned long' to 'long'

I don't see any conversion in that line.

Array subscripting is defined in terms of pointer arithmetic. buf[n]
is equivalent to *(buf+n), so the normal promotions are applied. In
this case they don't do anything, since the operands of "-" both
already have (we assume) type unsigned long. The subtraction produces
another unsigned long, which is added to the pointer. No long should
be involved.

-- Richard
 
R

Richard Tobin

buf[n] is equivalent to *(buf+n), so the normal promotions
are applied.
[/QUOTE]
That depends on how anal we want to be. Footnote #48 shows
that the *intent* is not to have the integer promotions
apply for the subscripting operation. Whether that can be
easily and umambiguously derived from the normative text
is another matter.

Surely the additive operators section makes this clear. The "usual
arithmetic conversions" (which include integer promotions) are applied
if both operands have arithmetic type, which is not the case here.
The definition of addition for a pointer and an integer is not in
terms of C's arithmetic so the particular integer type does not enter
into it. If P points to the i'th member of an array, and n is the
value of N, the P[N] points to the i+n'th member of the array,
regardless of the (integer) type of N.

In any case, there is no promotion from unsigned long to long.

-- Richard
 
B

Ben Bacarisse

buf[bufSize - (size_t) 1] = element; /* line 27 */
$ lint test.c
test.c:27: warning: converted from 'unsigned long' to 'long'

I don't see any conversion in that line.

Array subscripting is defined in terms of pointer arithmetic. buf[n]
is equivalent to *(buf+n), so the normal promotions are applied.

Nit: That is not my reading of 6.5.6. Para. 4 says "If both operands
have arithmetic type, the usual arithmetic conversions are performed
on them" but a pointer is not a arithmetic type (that's integer and
floating types). The paragraphs about adding an integer value to a
pointer say nothing about promotions.

[BTW, I call this is nit because, since the integer promotions
preserve value, I can't see how it could matterone way or the other.]
 
B

Ben Bacarisse

$ cat test.c
#include <stddef.h>
#include <stdlib.h>

void append(short);

short *buf;
size_t bufSize;

int main(void) {
if ((buf = malloc(bufSize = (size_t) 1)) == NULL) exit(1); /* out of
memory */

This allocates 1 byte.
*buf = 6;

and this uses more unless sizeof(short) == 1. I most implementation,
short is more than 1 byte in size.
append(28);
append(496);
free(buf);
return 0;
}

void append(short element) {
short *newBuf;

if ((size_t) -1 - (size_t) 1 < bufSize) exit(1); /* can't address
more */

This is a complex way of writing

if (bufSize == (size_t)-1)
if ((newBuf = realloc(buf, ++bufSize)) == NULL) {
free(buf);
exit(1); /* out of memory */
}
buf = newBuf;
buf[bufSize - (size_t) 1] = element; /* line 27 */

You don't need to convert 1 here. bufSize - 1 does the right thing.
}
$ lint test.c
test.c:27: warning: converted from 'unsigned long' to 'long'

Pass.

Two points: (1) size_t is fine as an index type. Just make sure you
don't subtract from a zero index. (2) A realloc for each new element
is costly. It is better to use a size multiplier (double the size or
use (bufSize * 3) / 2 or some such expression).
 
B

Ben Bacarisse

Richard Heathfield said:
Ben Bacarisse said:



If you use the latter, do remember to ensure that bufSize's initial
value is at least 2 :)

Yes. In fact I'd suggest a minimum rather larger than that. Exactly
what would depend on the distribution of sizes that the OP expects.

When I want to stick with small sizes I use a multiplier and add a
bit. For example s * 3 / 2 + 1 gives you the sequence 0, 1, 2, 4, 7,
11, 17, 26, 40...
 
C

CBFalconer

Ben said:
Yes. In fact I'd suggest a minimum rather larger than that.
Exactly what would depend on the distribution of sizes that the
OP expects.

When I want to stick with small sizes I use a multiplier and add
a bit. For example s * 3 / 2 + 1 gives you the sequence 0, 1, 2,
4, 7, 11, 17, 26, 40...

Tip. malloc systems often add a fixed size to the requested value
to keep track. That size is normally <= 16 (bytes), and that 16
bytes fits into the alignment requirements. Therefore memory is
likely to be more efficiently used if the allocation amount is a
power of 2 minus 16.
 
R

Richard Tobin

Array subscripting is defined in terms of pointer arithmetic. buf[n]
is equivalent to *(buf+n), so the normal promotions are applied.
[/QUOTE]
Nit: That is not my reading of 6.5.6.

Yes, I said the wrong thing there. The promotions are applied in the
evaluation of n (which was a subtraction in the OP's case), but as I
pointed out in another article there are no promotions in pointer
arithmetic because it's just defined in terms of the values.

-- Richard
 

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
474,145
Messages
2,570,826
Members
47,372
Latest member
LucretiaFo

Latest Threads

Top