D
David Hopwood
Wojtek said:Prove it.
That shouldn't be difficult to do by exhaustive search ;-)
Wojtek said:Prove it.
#include <stdio.h>cat main.c
#include <stdlib.h>
int main(int argc, char* argv[]) {
const int a[2][2] = {{1, 2}, {3, 4}}, *b = a[0];
const size_t n = sizeof(a)/sizeof(a[0][0]);
for (size_t j = 0; j < n; ++j)
fprintf(stdout, "b[%u] = %d\t", j, b[j]);
fprintf(stdout, "\n");
return EXIT_SUCCESS;
}
b[0] = 1 b[1] = 2 b[2] = 3 b[3] = 4gcc -Wall -std=c99 -pedantic -o main main.c
./main
This program ports to every platform
with a C99 compliant compiler.
In comp.lang.c Douglas A. Gwyn said:It is entirely possible
that a compiler can generate more efficient code if it
takes advantage of the declared size; for example, if an
architecture has a 64KB limit on segment size and the
array is declared smaller than that, then it will not be
necessary to generate code that copes with segment
boundaries (e.g. loading different segment base
addresses for different parts of the array).
An array
of arrays is guaranteed to have the storage contiguously
allocated (without extra padding), but not all elements
of each array can be accessed by indexing off a pointer
"based on" a pointer to a given element in a particular
array.
Ivan said:Does this mean that pointers that are results of array-to-pointer conversion
and any other pointers are somehow differ?
S.Tobias said:But I still don't see what should be wrong with this:
char *b = a[0];
b[2]; //equiv to *(b+2)
If that were not allowed, it would mean we cannot access
object `a' through char*.
Michael said:Hi pete
I don't see what difference it makes whether or not object a
even contains an int type. As long as object a is as big as an int
and also aligned for type int, I can access the object as (*(int*)&a)
regardless if a was declared as a structure or an array of floats.
With
int *b = (int *)&a;
b[3] isn't accessing an element of a,
b[3] is accessing the memory at (int*)&a + 3,
and treating it as an object of type int.
Assuming a in this case is not an array of any flavour
(or that you would have used the appropriate &a[0]...[0]):
OK.
That is exactly the point! b[3] or b+3 accesses this address
but it is not guaranteed that it may do so!
You just might try to access memory which you do not have
access to as it does not belong to the object you pointed b
to...
Douglas A. Gwyn said:If the compiler can see the array context then it is
allowed to take advantage of it, i.e. to generate
That is exactly the point! b[3] or b+3 accesses this address
but it is not guaranteed that it may do so!
You just might try to access memory which you do not have
access to as it does not belong to the object you pointed b
to...
I disagree.
new.c is a portable program.
/* BEGIN new.c */
#include <stdio.h>
int main(void)
{
int a[2][2] = {{1, 2}, {3, 4}}, *b = (int *)&a;
if (b == (int *)&a[1][1] - 3) {
puts("There's no chance that this program "
"does not own the memory at b[3]");
}
return 0;
}
/* END new.c */
In comp.lang.c Douglas A. Gwyn said:and partly it is to allow type-based nonaliasing
assumptions to be made by compilers (another matter
of code efficiency). It may be instructive to
long a[10], b[10], *p = a, *q = b;
if (a + 10 == b)
stmt_1
else
stmt_2
It is hard to see what could go wrong with such
tiny examples,
especially if you're not very
familiar with segment addressing, but if you start
to think in terms of arrays near, say, 64KB in size
the problems may become more evident.
E. Robert Tisdale said:If they are "getting away with" it, it's portable.
David said:That shouldn't be difficult to do by exhaustive search ;-)
Ivan A. Kosarev said:None of types designates objects.
Instead, objects are memory areas which are interpreted accordingly to their
types.
.. Since that, it's not important how we get a pointer pair to compare
it with relational operators; if they point to a single array (that is an
*object*, not a *type*), they can be compared with a defined result.
Again, since the array is a single object, a[1] + 2 and b + 4 are values
that point to the same object of the same type.
I don't see what difference it makes whether or not object a
even contains an int type. As long as object a is as big as an int
and also aligned for type int, I can access the object as (*(int*)&a)
regardless if a was declared as a structure or an array of floats.
James Kuyper said:"Ivan A. Kosarev" <[email protected]> wrote in message ....
It's valid to read a piece of memory using an lvalue of a type
compatible with the last lvalue used to write into that piece of
memory. Neither the read nor the write need have been done using
the same type that was declared for that piece of memory, as long
as the other relevant rules are obeyed (such as alignment).
Array types are types. Array objects are objects with array types.
...Again, since the array is a single object, a[1] + 2 and b + 4 are values
that point to the same object of the same type.
a[1]+2 points one past the end of the array object a[1], which happens to
be at the same location as the position one past the array object a. 'b'
points at the first element of the array object a[0]. It happens to point
at the same memory location as the start of the array object 'a', but it
has the wrong type to point at the first element of 'a'. Therefore, the
limits on what values can legally be added to 'b' are determined by the
number of elements in a[0], not the total number of elements of elements
in a. There is no array involved here which has four elements, and
therefore there isn't any pointer here for which it would be legal to add
3 to it. Therefore, b+4 isn't a legal expression, and it's meaningless to
With
int *b = (int *)&a;
b[3] isn't accessing an element of a,
b[3] is accessing the memory at (int*)&a + 3,
and treating it as an object of type int.
That is exactly the point! b[3] or b+3 accesses this address
but it is not guaranteed that it may do so!
You just might try to access memory which you do not have
access to as it does not belong to the object you pointed b
to...
I disagree.
new.c is a portable program.
#include <stdio.h>
int main(void)
{
int a[2][2] = {{1, 2}, {3, 4}}, *b = (int *)&a;
[etc.]if (b == (int *)&a[1][1] - 3) {
So you're saying you would allow:
float a[100];
int x = *(int *)&a;
(assuming correct alignment) ?
James said:If 'a' is a composite type whose first component has a type of 'int',
the standard specifies that (int*)&a points at that element. It
therefore inherits the range limitations on addition appropriate to
that array of which that 'int' is an element. If it's only a single
'int', it is treated as an array containing exactly one element.
If 'a' is NOT such a type, and if it is not an array of a character
type, the standard does not define where 'b' points. It could point
at an entirely different piece of memory; the only requirement is
that when it's cast back to the original type, it must again point at
'a'.
S.Tobias said:I think what you mean to say is that compiler is allowed
to assume that b[0] will not be changed between first assignment
and if() condition, since p does not point within b[]:
Is it true, that after (1) compiler *may* assume that a[1][0] is still 1,
because pa0 is "based" on a[0] (and implicitly has access only to that
sub-object), and after (2) it *has* *to* assume that something changed in
the entire a[][] array (and hence has to re-read a[1][0]), because pa is
"based" on a and has access to the whole object?
pete said:Does that imply that two objects the same size,
could have different alignment requirements?
Douglas said:They sure could. For example, long int and
float may well be the same size, but float
may have to be aligned on a 32-bit boundary
for purposes of the floating-point coprocessor,
while long int might be alignable on an 8-bit
boundary for purposes of the integer processor.
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.