array padding

B

buda

Hello,
Is the behaviour of indexing an array with a negative number (like a[-1])
defined by the standard?
 
V

Viktor Lofgren

buda said:
Hello,
Is the behaviour of indexing an array with a negative number (like a[-1])
defined by the standard?

Not 101% certain, but a[n] should point to *(a+(sizeof(*a)*n)), so it should
be *(a+(sizeof(a)*-1)), that is 1 memory-spot before a starts.
 
M

Martin Dickopp

buda said:
Is the behaviour of indexing an array with a negative number (like
a[-1]) defined by the standard?

If the expression refers to an existing array element, then yes.
Otherwise, the behavior is undefined.

For example, given the code

int b [3];
int *a = b + 1;

the expression `a [-1]' is valid and refers to the same object as
`b [0]'.

Martin
 
A

Allin Cottrell

buda said:
Hello,
Is the behaviour of indexing an array with a negative number (like a[-1])
defined by the standard?

It's undefined behaviour. See section 6.5.6 of the 1999 C standard.

Allin Cottrell
 
M

Martin Dickopp

Viktor Lofgren said:
buda said:
Hello,
Is the behaviour of indexing an array with a negative number (like
a[-1]) defined by the standard?

Not 101% certain, but a[n] should point to *(a+(sizeof(*a)*n)),

Your statement is misleading. First of all, `a [n]' is not necessarily
a pointer, so it's not necessarily pointing to anything. You probably
mean "the address of `a [n]' is the same as ...".

More importantly, the address of `a [n]' is the same as the address of
`*(a + n)', which is different from `*(a + (sizeof (*a) * n))' unless
`sizeof *a' happens to be 1. However the address of `a [n]' is the same
as the address of `*((char *)a + (sizeof (*a) * n))', i.e. the addresses
of `a' and `a [n]' differ by `sizeof (*a) * n' bytes.

Martin
 
V

Viktor Lofgren

Martin Dickopp said:
More importantly, the address of `a [n]' is the same as the address of
`*(a + n)', which is different from `*(a + (sizeof (*a) * n))' unless
`sizeof *a' happens to be 1. However the address of `a [n]' is the same
as the address of `*((char *)a + (sizeof (*a) * n))', i.e. the addresses
of `a' and `a [n]' differ by `sizeof (*a) * n' bytes.

No, if a is int_32*, a[n] = *(a + 4 * n).
For an example:

int* b = NULL;
printf("%d %d", &b[0], &b[1]);

prints "0 4" when executed, if a[n] would be *(a+n), it would print "0 1".
 
C

Christian Bau

Viktor Lofgren said:
Martin Dickopp said:
More importantly, the address of `a [n]' is the same as the address of
`*(a + n)', which is different from `*(a + (sizeof (*a) * n))' unless
`sizeof *a' happens to be 1. However the address of `a [n]' is the same
as the address of `*((char *)a + (sizeof (*a) * n))', i.e. the addresses
of `a' and `a [n]' differ by `sizeof (*a) * n' bytes.

No, if a is int_32*, a[n] = *(a + 4 * n).
For an example:

int* b = NULL;
printf("%d %d", &b[0], &b[1]);

prints "0 4" when executed, if a[n] would be *(a+n), it would print "0 1".

I suggest you try

int a [10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int n = 1;

printf ("%d %d\n", a [n], * (a + 4 * n));

and tell us what happens.
 
M

Martin Dickopp

Viktor Lofgren said:
Martin Dickopp said:
More importantly, the address of `a [n]' is the same as the address of
`*(a + n)', which is different from `*(a + (sizeof (*a) * n))' unless
`sizeof *a' happens to be 1. However the address of `a [n]' is the same
as the address of `*((char *)a + (sizeof (*a) * n))', i.e. the addresses
of `a' and `a [n]' differ by `sizeof (*a) * n' bytes.

No, if a is int_32*, a[n] = *(a + 4 * n).

No. Please look up in your C book what the effect of the `+' operator
is if one operand is a pointer and the other is an integer.
For an example:

int* b = NULL;
printf("%d %d", &b[0], &b[1]);

prints "0 4" when executed, if a[n] would be *(a+n), it would print "0 1".

This code fragment invokes undefined behavior for two reasons: First of
all, the "%d" specifier expects an `int' argument, but `&b[0]' and
`&b[1]' have type `int *'. Secondly, it is undefined behavior to add
something to a null pointer, as is done in the expression `&b[1]'.

Since the code invokes undefined behavior, anything could have happened,
including printing "0 4", printing "0 1", or printing a Shakespearean
sonnet.

If you really want a program that demonstrates that you're wrong, try
this one:


#include <stdio.h>

int main (void)
{
int a [4];
printf ("address of a [1] is %p\n", (void *)&a [1]);
printf ("address of *(a + 1) is %p\n", (void *)&*(a + 1));
printf ("address of *(a + 4 * 1) is %p\n", (void *)&*(a + 4 * 1));
return 0;
}


Martin
 
G

Gordon Burditt

More importantly, the address of `a [n]' is the same as the address of
`*(a + n)', which is different from `*(a + (sizeof (*a) * n))' unless
`sizeof *a' happens to be 1. However the address of `a [n]' is the same
as the address of `*((char *)a + (sizeof (*a) * n))', i.e. the addresses
of `a' and `a [n]' differ by `sizeof (*a) * n' bytes.

No, if a is int_32*, a[n] = *(a + 4 * n).

No. I think you mean a[n] = *(a addl (4 mull n))
where addl and mull are assembly-language arithmetic operators.
For an example:

int* b = NULL;
printf("%d %d", &b[0], &b[1]);

prints "0 4" when executed, if a[n] would be *(a+n), it would print "0 1".

C operators are different from assembly-language ones, especially
when pointers are involved.

Also, there is no guarantee that sizeof(a 32-bit integer type) does not
equal 1.

Gordon L. Burditt
 
S

Stephen L.

Allin said:
Hello,
Is the behaviour of indexing an array with a negative number (like a[-1])
defined by the standard?

It's undefined behaviour. See section 6.5.6 of the 1999 C standard.

Allin Cottrell

Maybe you could give us a wee bit more to go on...
Since we might be looking at two different documents,
are you refering to the section titled -

"6.5.6 Additive operators"?

I'm not sure how the following is "undefined behaviour"...

/********************************************/

#include <stdio.h>


int
main()
{
char str[] = "1234567890";
char *p = &str[ sizeof (str) - 1 ]; /* `p' points to string's
NULL */


printf("Character should be '0', '%c'.\n", p[ -1 ]);
printf("Character should be '9', '%c'.\n", p[ -2 ]);

printf("Character should be '0', '%c'\n", *(p - 1));
printf("Character should be '9', '%c'\n", *(p - 2));

printf("Same as above, '0', '%c'.\n", *--p); /* Is _this_ undefined
too? */
printf("Same as above, '9', '%c'.\n", *--p);

return (0);
}
 
A

Arthur J. O'Dwyer

Allin said:
buda said:
Is the behaviour of indexing an array with a negative number (like a[-1])
defined by the standard?

It's undefined behaviour. See section 6.5.6 of the 1999 C standard.

I'm not sure how the following is "undefined behaviour"...

It's not. However, if 'a' is, as the OP said, an array name, then
indeed indexing 'a' with a negative subscript will dereference a pointer
that's not pointing to an object. E.g.,

foo a[bar]; a[-1];

is *always*, without exception, undefined behavior.

Doing the same thing with a pointer, e.g.

baz *p = quux; p[-1];

may or may not invoke UB, depending on the value of 'quux'. In your
example, there is no undefined behavior.

-Arthur

#include <stdio.h>

int
main()
{
char str[] = "1234567890";
char *p = &str[ sizeof (str) - 1 ]; /* `p' points to string's
NULL */


printf("Character should be '0', '%c'.\n", p[ -1 ]);
printf("Character should be '9', '%c'.\n", p[ -2 ]);

printf("Character should be '0', '%c'\n", *(p - 1));
printf("Character should be '9', '%c'\n", *(p - 2));

printf("Same as above, '0', '%c'.\n", *--p); /* Is _this_ undefined
too? */
printf("Same as above, '9', '%c'.\n", *--p);

return (0);
}
 
M

Martin Dickopp

Stephen L. said:
char str[] = "1234567890";
char *p = &str[ sizeof (str) - 1 ]; /* `p' points to string's
NULL */

ITYM null character instead of NULL. (NULL is a macro which expands to
a null /pointer/ constant.)

Martin
 
C

Chris Torek

For an example:

int* b = NULL;
printf("%d %d", &b[0], &b[1]);

prints "0 4" when executed, if a[n] would be *(a+n), it would print "0 1".

I ran this on a Data General Eclipse[%] and it printed:

1879048192 1879048194

Can you explain this?

(Convert the above to hex for a big hint. The numbers are 0x70000000
and 0x70000002 respectively. The facts that sizeof(int) is 4 and
that "int *" uses "word pointers", with 16-bit words, are both
important.)

[% Actually I do not have access to one, but this is what it might
print, if I remember right. I made up a segment-and-ring number
of 0x7 and am not sure that this is correct for user-mode code, or
even the right number of bits.]
 
K

Keith Thompson

buda said:
Hello,
Is the behaviour of indexing an array with a negative number (like a[-1])
defined by the standard?

If a is an array object, then evaluating a[-1] invokes undefined
behavior.

Array indexing is really a binary operation ("binary" meaning it takes
two operands); the left operand is a pointer to some object type, and
the right operand is an integer (or vice versa; see below). x[y] is
equivalent to *(x+y). Since x is a pointer and y is an integer, the
"+" performs pointer arithmetic.

If "a" points into the middle of an array object, "a[-1]" yields the
value of the array element just before the one that "a" points to.

It may seem odd that the left operand is expected to be a pointer, not
an array. It works for arrays because, in most expression contexts,
an array name is converted to a pointer to its first element.

(x[y] is equivalent to *(x+y). Since addition is commutative, *(x+y)
is equivalent to *(y+x), which is equivalent to y[x]. Thus
5["abcdef"] is a legal expression, equal to 'f'. This is interesting,
but not particularly useful.)

See section 6 of the C FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
for more information. While you're there, read the whole thing.
 
C

Charles Richmond

buda said:
Hello,
Is the behaviour of indexing an array with a negative number (like a[-1])
defined by the standard?
You can do something like the following;

#include <stdio.h>
#include <stdlib.h>

int main()
{
int *a, *b;

b = malloc(21 * sizeof int);

a = b + 11;

a[5] = 42;

a[-5] = 24;

printf("The values are %d and %d\n",a[5],a[-5]);
}

This technique can be useful when converting a Pascal program
that is using negative subscripts.
 
C

Chris Torek

In said:
I ran this on a Data General Eclipse[%] ...
[% Actually I do not have access to one, but this is what it might
print, if I remember right.

Did anyone implement standard C on it? How about K&R C?

I am not at all sure about Standard C. The machine I used ran
a (somewhat bizarre and twisted variation on) 4.2BSD Unix. The
C compiler implemented everything required to compile typical
Unix programs. I think that covers "K&R C" and then some -- the
compiler had enumerations and "unsigned char", for instance.

Quite a lot of our C code had to be fixed up not to make assumptions
about pointer formats.

Besides the pointer trickiness, the main thing I remember about
the Eclipse is that the output from perror() was broken. It printed
a two digit error number, followed by no whitespace, followed by
the string, so that one would get things like:

prog: cannot open foo.dat: 02No such file or directory

(I also remember something about bogus newlines, perhaps before the
"02".)

(This machine and the Pyramid were responsible for our group at
the University of Maryland making numerous fixes to varous programs.
The Pyramid found non-pointer bugs. For instance, MH used the
interesting calling sequence "parameter passing by register
assumption"[%], which was impossible on the Pyramid due to its
register windows. The Pyramid also exposed all the programs that
failed to "return 0" or "exit(0)" from main. Return values from
functions had to be stored in register "pr0" in the register-window
assigned to that function, and calling some other function did not
affect one's own pr0, only one's tr0. Hence, programs that on the
VAX returned whatever was left in r0 -- which was the return value
from the most-recently-called function -- instead returned their
first argument. For main(), this was the parameter argc.)

[% An illustration, not necessarily the actual MH code and using
ANSI C syntax rather than Classic C:

void f1(struct S *param) {
register int a, b;
register FILE *some_file;
...
some_file = fopen("some_path", "w");
f2(param, a);
...
}

void f2(register struct S *param, register int a) {
register FILE *fp; /* NOTE: NOT INITIALIZED! */
...
fprintf(fp, "%s: %d\n", param->zig, a);
...
}

This worked on the VAX, and even the PDP-11, because the machine's
registers were handed out in a fixed, known order. On the VAX,
"some_file" wound up in r9; on the PDP-11 it was in r3. In each
case, declaring "fp" third in f2() caused the C compiler to reserve
the same register -- which still held the opened FILE *! The VAX
C compiler gave you six registers, while the PDP-11 gave you only
three, so the actual "parameter passing by register assumption" in
MH was definitely in the first six "register" variables, and almost
certainly in the first three.]
 
E

EventHelix.com

C will allow you to use a negative index. The index into an array is
signed integer. I guess you can use negative indices if you make sure
that the memory before the start of the array is allocated for this.

I remember seeing use of negative in Tanenbaum's MINIX book. The
positive indices were used as user task pids and negative indices
were used for MINIX tasks.

Sandeep
 
A

Al Bowers

EventHelix.com said:
... The index into an array is
signed integer. I guess you can use negative indices if you make sure
that the memory before the start of the array is allocated for this.

Doing this little trick is not C. A resource other than the
the ISO/IEC Internation Standard may suggest this and your compiler may
accept it in a way you expect. But that does not make it C. The C
Language describes this as undefined behavior.

The Standard specifically describes many circumstances of
undefined behavor. The following circumstance seems to make operation
clearly UB.

— Addition or subtraction of a pointer into, or just beyond,
an array object and an integer type produces a result that
does not point into, or just beyond, the same array object (6.5.6).
 
K

Keith Thompson

C will allow you to use a negative index. The index into an array is
signed integer. I guess you can use negative indices if you make sure
that the memory before the start of the array is allocated for this.

I remember seeing use of negative in Tanenbaum's MINIX book. The
positive indices were used as user task pids and negative indices
were used for MINIX tasks.

I'll bet that the "array" being indexed with a negative integer was
actually a pointer into the middle of an array object.
 

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

Forum statistics

Threads
474,142
Messages
2,570,820
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top