By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,963 Members | 1,902 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,963 IT Pros & Developers. It's quick & easy.

multi dimensional arrays as one dimension array

P: n/a
The subject might be misleading.
Regardless, is this code valid:

#include <stdio.h>

void f(double *p, size_t size) { while(size--) printf("%f\n", *p++); }
int main(void) {
double array[2][1] = { { 3.14 }, { 42.6 } };
f((double *)array, sizeof array / sizeof **array);
return 0;
}

Assuming casting double [2][1] to double * is implementation defined
or undefined behavior, replace the cast with (void *).

Since arrays are not allowed to have padding bytes in between of
elements, it seems valid to me.
Aug 29 '08 #1
Share this Question
Share on Google+
152 Replies


P: n/a
vi******@gmail.com wrote:
The subject might be misleading.
Regardless, is this code valid:

#include <stdio.h>

void f(double *p, size_t size) { while(size--) printf("%f\n", *p++); }
int main(void) {
double array[2][1] = { { 3.14 }, { 42.6 } };
f((double *)array, sizeof array / sizeof **array);
return 0;
}

Assuming casting double [2][1] to double * is implementation defined
or undefined behavior, replace the cast with (void *).

Since arrays are not allowed to have padding bytes in between of
elements, it seems valid to me.
Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.

--
pete
Aug 29 '08 #2

P: n/a
On Aug 29, 6:39 am, pete <pfil...@mindspring.comwrote:
vipps...@gmail.com wrote:
The subject might be misleading.
Regardless, is this code valid:
#include <stdio.h>
void f(double *p, size_t size) { while(size--) printf("%f\n", *p++); }
int main(void) {
double array[2][1] = { { 3.14 }, { 42.6 } };
f((double *)array, sizeof array / sizeof **array);
return 0;
}
Assuming casting double [2][1] to double * is implementation defined
or undefined behavior, replace the cast with (void *).
Since arrays are not allowed to have padding bytes in between of
elements, it seems valid to me.

Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.
So as I understand it you are saying my code invokes undefined
behavior.
In which hypothetical (or real, if such implementation does exist)
implementation my code won't work, and why?
Aug 29 '08 #3

P: n/a
vi******@gmail.com wrote:
On Aug 29, 6:39 am, pete <pfil...@mindspring.comwrote:
>vipps...@gmail.com wrote:
>>The subject might be misleading.
Regardless, is this code valid:
#include <stdio.h>
void f(double *p, size_t size) { while(size--) printf("%f\n", *p++); }
int main(void) {
double array[2][1] = { { 3.14 }, { 42.6 } };
f((double *)array, sizeof array / sizeof **array);
return 0;
}
Assuming casting double [2][1] to double * is implementation defined
or undefined behavior, replace the cast with (void *).
Since arrays are not allowed to have padding bytes in between of
elements, it seems valid to me.
Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.

So as I understand it you are saying my code invokes undefined
behavior.
In which hypothetical (or real, if such implementation does exist)
implementation my code won't work, and why?
I don't know.
I think it would be more difficult to design a system
where it wouldn't work, than to design one where it would.

Think of it as being allowed not to work.

--
pete
Aug 29 '08 #4

P: n/a
On Aug 28, 8:15 pm, vipps...@gmail.com wrote:
The subject might be misleading.
Regardless, is this code valid:

#include <stdio.h>

void f(double *p, size_t size) { while(size--) printf("%f\n", *p++); }
int main(void) {
double array[2][1] = { { 3.14 }, { 42.6 } };
f((double *)array, sizeof array / sizeof **array);
return 0;

}

Assuming casting double [2][1] to double * is implementation defined
or undefined behavior, replace the cast with (void *).
Changing the cast to void* only creates more work for the compiler.
Unless it is smart enough to optimize away the first step, it must
first convert array (which in this context is identical to &array[0]
and has type "double (*)[1]") to void* to satisfy the cast and then
convert that to double* to satisfy the prototype.

The only issue about pointer conversions is if the value is properly
aligned for the resulting type and the value of the expression array
is guaranteed to be properly aligned for a double* since the value
(disregarding type) is exactly the same as &array[0][0]..
>
Since arrays are not allowed to have padding bytes in between of
elements, it seems valid to me.
If your system has built in hardware assist for bounds checking, it
would be reasonable for the "bounds registers" to contain the start
and end addresses of array[0]. Eventually your p++ would be outside
this range (even though it is still within array as a whole). While
this is a perfectly valid value attempts to dereference it should be
trapped by the bounds checking logic in the hardware.

Whether such a system exists is a practical issue
Aug 29 '08 #5

P: n/a
vi******@gmail.com wrote:
On Aug 29, 6:39 am, pete <pfil...@mindspring.comwrote:
>vipps...@gmail.com wrote:
>>The subject might be misleading.
Regardless, is this code valid:
#include <stdio.h>
void f(double *p, size_t size) { while(size--) printf("%f\n", *p++); }
int main(void) {
double array[2][1] = { { 3.14 }, { 42.6 } };
f((double *)array, sizeof array / sizeof **array);
return 0;
}
Assuming casting double [2][1] to double * is implementation defined
or undefined behavior, replace the cast with (void *).
Since arrays are not allowed to have padding bytes in between of
elements, it seems valid to me.
Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.

So as I understand it you are saying my code invokes undefined
behavior.
In which hypothetical (or real, if such implementation does exist)
implementation my code won't work, and why?
The key point is the pointer conversion. At the point where that
conversion occurs, the compiler knows that (double*)array == array[0].
It's undefined if any number greater than 1 is added to that pointer
value, and also if that pointer is dereferenced after adding 1 to it.

Because the behavior is undefined, it's possible for a conforming
implementation to provide a run-time bounds check. This would require
the use of some mechanism such as a "fat" pointer, which contains not
only the information about where it points, but also information about
the upper and lower limits on where it can point. The implementation can
set the limits on the pointer value created by that conversion, based
upon the limits for array[0].

Implementations with support for run-time bounds checking are rare; the
performance cost is significant, it's almost always optional, and
usually not the default option, so you're unlikely to run into this
issue by accident.

The more tricky possibility is also something you're far more likely to
run into. Because the behavior is undefined in those cases, a compiler
is allowed to generate code which is optimized in a way that assumes
that those cases don't actually come up; because it makes that
assumption, such code can fail catastrophically if that assumption is
violated.

This is most likely to occur as the result of anti-aliasing assumptions.
The compiler is allowed to generate code which assumes that array[0][i]
is never an alias for array[1][j], regardless of the values of i and j.
As a result, it can drop anti-aliasing checks from code that would need
such checks if that assumption could be violated without making the
behavior undefined.

I don't see any way for that to come up in this particular example, but
in more complicated cases it can come up. If 'p' and 'array' were both
in scope at the same place somewhere in the code, the compiler would not
be required to prevent the problems that might occur if p[j] and
array[1][i] happened to refer to the same location in memory. It is
required to cover the possibility that p[j] and array[0][i] refer to the
same object, but only if 'i' and 'j' are both 0. It's also required to
handle the possibility that p+j refers to the same location as
array[0][i], but only if 'i' and 'j' are both in the range [0,1].
Aug 29 '08 #6

P: n/a
On Aug 29, 6:15 am, vipps...@gmail.com wrote:
Message-ID: <38b37f10-252e-48f8-bffa-
cc**********@j22g2000hsf.googlegroups.com>

Thanks everyone.
Aug 29 '08 #7

P: n/a
On Thu, 28 Aug 2008 23:39:54 -0400, pete <pf*****@mindspring.com>
wrote:
>
Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.
I am trying to understand your answer. Are you saying that the
original code will not necessarily work in a conforming compiler
because there is no guarantee in the standard that the row slices will
be exactly next to each other in memory (i.e., there may be padding
added to each row that may not be a multiple of sizeof(double))? But
at the same time if double was replaced with char, i.e.,

#include <stdio.h>
void f(char *p, size_t size) { while(size--) printf("%c\n", *p++); }
int main(void) {
char array[2][1] = { { 'a' }, { 'b' } };
f((char *)array, sizeof array / sizeof **array);
return 0;
}

then for this particular case the row slices are required by the
standard to be next to each other in memory so the individual stepping
will work in the called function? Or are you saying that for the char
case there may still be padding between the row slices but the
individual stepping will work because the padding will always be a
multiple of sizeof(char) (i.e., 1), and that the stepping in the
called function will just include the padded characters if they are
present?

i.e., in either case the called function may not be doing what you
intended if there is padded memory present between the rows, but in
the case of double or other non-character type it may even bomb.

Do I understand your answer correctly?

James Tursa
Aug 31 '08 #8

P: n/a
On Fri, 29 Aug 2008 11:08:00 GMT, James Kuyper
<ja*********@verizon.netwrote:
>
The key point is the pointer conversion. At the point where that
conversion occurs, the compiler knows that (double*)array == array[0].
It's undefined if any number greater than 1 is added to that pointer
value, and also if that pointer is dereferenced after adding 1 to it.
Trying to understand your answer as it relates to the original post. I
don't see how the original function gets an address 2 beyond the end,
or 1 beyond the end and attempts to dereference it, as you seem to be
saying. Can you point this out? Did I misunderstand you?

James Tursa
Aug 31 '08 #9

P: n/a
On Aug 31, 8:02 pm, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
On Thu, 28 Aug 2008 23:39:54 -0400, pete <pfil...@mindspring.com>
wrote:
Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.

I am trying to understand your answer. Are you saying that the
original code will not necessarily work in a conforming compiler
because there is no guarantee in the standard that the row slices will
be exactly next to each other in memory (i.e., there may be padding
added to each row that may not be a multiple of sizeof(double))? But
at the same time if double was replaced with char, i.e.,

#include <stdio.h>
void f(char *p, size_t size) { while(size--) printf("%c\n", *p++); }
int main(void) {
char array[2][1] = { { 'a' }, { 'b' } };
f((char *)array, sizeof array / sizeof **array);
return 0;

}

then for this particular case the row slices are required by the
standard to be next to each other in memory so the individual stepping
will work in the called function? Or are you saying that for the char
case there may still be padding between the row slices but the
individual stepping will work because the padding will always be a
multiple of sizeof(char) (i.e., 1), and that the stepping in the
called function will just include the padded characters if they are
present?

i.e., in either case the called function may not be doing what you
intended if there is padded memory present between the rows, but in
the case of double or other non-character type it may even bomb.

Do I understand your answer correctly?
That code of yours invokes undefined behavior, if char is signed.
You have to change the type of p to unsigned char.
Also, it would only be meaningful if you did not divide by sizeof
**array.

'pete' did not really answer my question. Instead he spoke for object
representations.
What pete really meant is that you can treat any pointer to object as
an array of unsigned char, to observe its representation.
Aug 31 '08 #10

P: n/a
James Tursa <ac*******************@hotmail.comwrites:
On Thu, 28 Aug 2008 23:39:54 -0400, pete <pf*****@mindspring.com>
wrote:
>Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.

I am trying to understand your answer. Are you saying that the
original code will not necessarily work in a conforming compiler
because there is no guarantee in the standard that the row slices will
be exactly next to each other in memory (i.e., there may be padding
added to each row that may not be a multiple of sizeof(double))?
No. There cannot be padding between array elements; in particular,
given:

double arr[10][10];

the size of arr is guaranteed to be exactly 100*sizeof(double).

Padding isn't the issue. The issue is that the standard doesn't
require implementations to support indexing past the end of an array.
So if I write

arr[0][15]

I'm trying to refer to an element of arr[0] that doesn't exist.
There's a valid object, accessible as arr[1][5], at the intended
location in memory -- and *most* C compilers will let you access that
object either as arr[0][15] or as arr[1][5]. But arr[1][5] is
guaranteed to work, and arr[0][15] isn't, because it attempts to index
beyond the end of the double[10] array arr[0].

In other words, implementations are allowed, but not required, to
perform bounds checking.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Aug 31 '08 #11

P: n/a
On Sun, 31 Aug 2008 10:35:05 -0700 (PDT), vi******@gmail.com wrote:
>On Aug 31, 8:02 pm, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
>On Thu, 28 Aug 2008 23:39:54 -0400, pete <pfil...@mindspring.com>
wrote:
>Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.

I am trying to understand your answer. Are you saying that the
original code will not necessarily work in a conforming compiler
because there is no guarantee in the standard that the row slices will
be exactly next to each other in memory (i.e., there may be padding
added to each row that may not be a multiple of sizeof(double))? But
at the same time if double was replaced with char, i.e.,

#include <stdio.h>
void f(char *p, size_t size) { while(size--) printf("%c\n", *p++); }
int main(void) {
char array[2][1] = { { 'a' }, { 'b' } };
f((char *)array, sizeof array / sizeof **array);
return 0;

}

then for this particular case the row slices are required by the
standard to be next to each other in memory so the individual stepping
will work in the called function? Or are you saying that for the char
case there may still be padding between the row slices but the
individual stepping will work because the padding will always be a
multiple of sizeof(char) (i.e., 1), and that the stepping in the
called function will just include the padded characters if they are
present?

i.e., in either case the called function may not be doing what you
intended if there is padded memory present between the rows, but in
the case of double or other non-character type it may even bomb.

Do I understand your answer correctly?

That code of yours invokes undefined behavior, if char is signed.
You have to change the type of p to unsigned char.
Also, it would only be meaningful if you did not divide by sizeof
**array.
What don't you like about sizeof **array ?
>'pete' did not really answer my question. Instead he spoke for object
representations.
What pete really meant is that you can treat any pointer to object as
an array of unsigned char, to observe its representation.
OK, that's fine for objects, but that doesn't answer my question. What
is it about 2-dimensional (or multi-dimensional) arrays of double that
does not allow them to be stepped through with a double* ? And
ultimately, I would also ask if it is safe/conforming to use memcpy or
the like to copy values from/to such an array wholesale. e.g., is it
OK to have the following and be guaranteed to get all of the values
copied correctly and get at them with dp[0], dp[1], etc.:

double x[2][3];
double *dp;
dp = malloc(6*sizeof(double));
(some code to fill in values of x)
memcpy(dp,x,6*sizeof(double));

James Tursa
Aug 31 '08 #12

P: n/a
On Aug 31, 10:16 pm, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
On Sun, 31 Aug 2008 10:35:05 -0700 (PDT), vipps...@gmail.com wrote:
On Aug 31, 8:02 pm, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
On Thu, 28 Aug 2008 23:39:54 -0400, pete <pfil...@mindspring.com>
wrote:
Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.
I am trying to understand your answer. Are you saying that the
original code will not necessarily work in a conforming compiler
because there is no guarantee in the standard that the row slices will
be exactly next to each other in memory (i.e., there may be padding
added to each row that may not be a multiple of sizeof(double))? But
at the same time if double was replaced with char, i.e.,
#include <stdio.h>
void f(char *p, size_t size) { while(size--) printf("%c\n", *p++); }
int main(void) {
char array[2][1] = { { 'a' }, { 'b' } };
f((char *)array, sizeof array / sizeof **array);
return 0;
}
then for this particular case the row slices are required by the
standard to be next to each other in memory so the individual stepping
will work in the called function? Or are you saying that for the char
case there may still be padding between the row slices but the
individual stepping will work because the padding will always be a
multiple of sizeof(char) (i.e., 1), and that the stepping in the
called function will just include the padded characters if they are
present?
i.e., in either case the called function may not be doing what you
intended if there is padded memory present between the rows, but in
the case of double or other non-character type it may even bomb.
Do I understand your answer correctly?
That code of yours invokes undefined behavior, if char is signed.
You have to change the type of p to unsigned char.
Also, it would only be meaningful if you did not divide by sizeof
**array.

What don't you like about sizeof **array ?
The object representation of an object is the unsigned char array[0]
to [sizeof object - 1]
If you divide with sizeof **array, you won't get all of the
representation. (unless sizeof(double) == 1)
'pete' did not really answer my question. Instead he spoke for object
representations.
What pete really meant is that you can treat any pointer to object as
an array of unsigned char, to observe its representation.

OK, that's fine for objects, but that doesn't answer my question. What
is it about 2-dimensional (or multi-dimensional) arrays of double that
does not allow them to be stepped through with a double* ? And
ultimately, I would also ask if it is safe/conforming to use memcpy or
the like to copy values from/to such an array wholesale. e.g., is it
OK to have the following and be guaranteed to get all of the values
copied correctly and get at them with dp[0], dp[1], etc.:

double x[2][3];
double *dp;
dp = malloc(6*sizeof(double));
(some code to fill in values of x)
memcpy(dp,x,6*sizeof(double));
mem* uses unsigned char. What is wrong is explained in the previous
posts.
Aug 31 '08 #13

P: n/a
On Sun, 31 Aug 2008 11:43:23 -0700, Keith Thompson <ks***@mib.org>
wrote:
>James Tursa <ac*******************@hotmail.comwrites:
>On Thu, 28 Aug 2008 23:39:54 -0400, pete <pf*****@mindspring.com>
wrote:
>>Stepping through a one dimensional array
and on through a consecutive one dimensional array
is only defined for elements of character type
and only because
any object can be treated as an array of character type.

I am trying to understand your answer. Are you saying that the
original code will not necessarily work in a conforming compiler
because there is no guarantee in the standard that the row slices will
be exactly next to each other in memory (i.e., there may be padding
added to each row that may not be a multiple of sizeof(double))?

No. There cannot be padding between array elements; in particular,
given:

double arr[10][10];

the size of arr is guaranteed to be exactly 100*sizeof(double).

Padding isn't the issue.
Well, I didn't really believe that padding was an issue but that's
what seem to be implied by the response.
The issue is that the standard doesn't
require implementations to support indexing past the end of an array.
So if I write

arr[0][15]

I'm trying to refer to an element of arr[0] that doesn't exist.
There's a valid object, accessible as arr[1][5], at the intended
location in memory -- and *most* C compilers will let you access that
object either as arr[0][15] or as arr[1][5]. But arr[1][5] is
guaranteed to work, and arr[0][15] isn't, because it attempts to index
beyond the end of the double[10] array arr[0].

In other words, implementations are allowed, but not required, to
perform bounds checking.
Well, I am still trying to understand how that argument applies to the
original OP posted code. Your argument is based on using arr directly.
But you seem to be saying that OP can't do this:

double *dp = (double *) arr;

and then traverse the entire array using dp. Is that what you are
saying?

James Tursa
Aug 31 '08 #14

P: n/a
On Sun, 31 Aug 2008 12:32:28 -0700 (PDT), vi******@gmail.com wrote:
>>
double x[2][3];
double *dp;
dp = malloc(6*sizeof(double));
(some code to fill in values of x)
memcpy(dp,x,6*sizeof(double));

mem* uses unsigned char. What is wrong is explained in the previous
posts.
See Harald's posted reply ... he thinks this is OK, and I tend to
agree with him.

James Tursa
Aug 31 '08 #15

P: n/a
On Aug 31, 11:25 pm, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
On Sun, 31 Aug 2008 12:32:28 -0700 (PDT), vipps...@gmail.com wrote:
double x[2][3];
double *dp;
dp = malloc(6*sizeof(double));
(some code to fill in values of x)
memcpy(dp,x,6*sizeof(double));
mem* uses unsigned char. What is wrong is explained in the previous
posts.

See Harald's posted reply ... he thinks this is OK, and I tend to
agree with him.
It *is* okay because mem* uses unsigned char.
Aug 31 '08 #16

P: n/a
James Tursa <ac*******************@hotmail.comwrites:
On Sun, 31 Aug 2008 11:43:23 -0700, Keith Thompson <ks***@mib.org>
wrote:
[...]
>>No. There cannot be padding between array elements; in particular,
given:

double arr[10][10];

the size of arr is guaranteed to be exactly 100*sizeof(double).

Padding isn't the issue.

Well, I didn't really believe that padding was an issue but that's
what seem to be implied by the response.
> The issue is that the standard doesn't
require implementations to support indexing past the end of an array.
So if I write

arr[0][15]

I'm trying to refer to an element of arr[0] that doesn't exist.
There's a valid object, accessible as arr[1][5], at the intended
location in memory -- and *most* C compilers will let you access that
object either as arr[0][15] or as arr[1][5]. But arr[1][5] is
guaranteed to work, and arr[0][15] isn't, because it attempts to index
beyond the end of the double[10] array arr[0].

In other words, implementations are allowed, but not required, to
perform bounds checking.

Well, I am still trying to understand how that argument applies to the
original OP posted code. Your argument is based on using arr directly.
But you seem to be saying that OP can't do this:

double *dp = (double *) arr;

and then traverse the entire array using dp. Is that what you are
saying?
Close. I'm saying that you most likely *can* get away with that
(treating an array of array of double as if it were an array of
double), but the standard doesn't require an implementation to make it
work. The most likely ways it can fail are if an implementation
performs run-time or compile-time bounds checking, or if an optimizer
assumes (as it's permitted to do) that you're not doing something like
this, causing the generated code not to do what you expected it to do.

Harald's explanation elsewhere in this thread makes the point more
clearly than I did, I think:

The fact that double[2][3] doesn't have elements such as
x[0][5]. There must be a valid double, 5*sizeof(double) bytes into
x. However, x[0][5] doesn't mean just that. x[0][5] (or
((double*)x)[5]) means you're looking 5*sizeof(double) bytes into
x[0]. x[0] doesn't have that many elements.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Aug 31 '08 #17

P: n/a
James Tursa <ac*******************@hotmail.comwrites:
On Sun, 31 Aug 2008 11:43:23 -0700, Keith Thompson <ks***@mib.org>
wrote:
[...]
>>No. There cannot be padding between array elements; in particular,
given:

double arr[10][10];

the size of arr is guaranteed to be exactly 100*sizeof(double).

Padding isn't the issue.

Well, I didn't really believe that padding was an issue but that's
what seem to be implied by the response.
> The issue is that the standard doesn't
require implementations to support indexing past the end of an array.
So if I write

arr[0][15]

I'm trying to refer to an element of arr[0] that doesn't exist.
There's a valid object, accessible as arr[1][5], at the intended
location in memory -- and *most* C compilers will let you access that
object either as arr[0][15] or as arr[1][5]. But arr[1][5] is
guaranteed to work, and arr[0][15] isn't, because it attempts to index
beyond the end of the double[10] array arr[0].

In other words, implementations are allowed, but not required, to
perform bounds checking.

Well, I am still trying to understand how that argument applies to the
original OP posted code. Your argument is based on using arr directly.
But you seem to be saying that OP can't do this:

double *dp = (double *) arr;

and then traverse the entire array using dp. Is that what you are
saying?
Close. I'm saying that you most likely *can* get away with that
(treating an array of array of double as if it were an array of
double), but the standard doesn't require an implementation to make it
work. The most likely ways it can fail are if an implementation
performs run-time or compile-time bounds checking, or if an optimizer
assumes (as it's permitted to do) that you're not doing something like
this, causing the generated code not to do what you expected it to do.

Harald's explanation elsewhere in this thread makes the point more
clearly than I did, I think:

The fact that double[2][3] doesn't have elements such as
x[0][5]. There must be a valid double, 5*sizeof(double) bytes into
x. However, x[0][5] doesn't mean just that. x[0][5] (or
((double*)x)[5]) means you're looking 5*sizeof(double) bytes into
x[0]. x[0] doesn't have that many elements.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Aug 31 '08 #18

P: n/a
On Sun, 31 Aug 2008 20:20:37 +0000, James Tursa wrote:
So you are saying that x[0][5] means exactly the same thing to the
compiler as ((double*)x)[5] ?
Yes, because (double*)x is a pointer to x[0][0].

(Actually, since the behaviour is undefined, it is allowed and
realistically possible for the compiler to treat the two differently, for
many possible reasons, but I'm not aware of any relevant specific details.)
I thought x[0] would be an array of 3
doubles, whereas (double*)x would be a plain double*.
Well, (double*)x is a plain double*, just not one into the whole array.
The only way I can think of to get overlapping arrays in the way you're
looking for is by using a union:

union {
double singledim[6];
double multidim[2][3];
} x;

but this is only possible if you know the length of the array at compile
time. Do you?
Aug 31 '08 #19

P: n/a
On Aug 31, 11:45 pm, Keith Thompson <ks...@mib.orgwrote:

<snip>

In case you don't see it, your message appeared twice.
Aug 31 '08 #20

P: n/a
On Aug 31, 11:47 pm, Harald van Dk <true...@gmail.comwrote:
<snip>
The only way I can think of to get overlapping arrays in the way you're
looking for is by using a union:

union {
double singledim[6];
double multidim[2][3];

} x;

but this is only possible if you know the length of the array at compile
time. Do you?
What about C99's VLAs?

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

int main(void) {

int x = 5;
int y = 10;

union { double my1D[x * y], my2D[x][y]; } *p = malloc(sizeof
*p);
if(p == NULL) return EXIT_FAILURE;
free(p);
return 0;
}

Aug 31 '08 #21

P: n/a
Keith Thompson <ks***@mib.orgwrites:
[the same thing twice]

Sorry about the double post.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Aug 31 '08 #22

P: n/a
On Sun, 31 Aug 2008 13:53:18 -0700, vippstar wrote:
On Aug 31, 11:47 pm, Harald van Dijk <true...@gmail.comwrote: <snip>
>The only way I can think of to get overlapping arrays in the way you're
looking for is by using a union:

union {
double singledim[6];
double multidim[2][3];

} x;

but this is only possible if you know the length of the array at
compile time. Do you?

What about C99's VLAs?
VLAs aren't allowed as structure or union members. I can't find the
normative wording in the standard (references are appreciated), but the
example in 6.7.5.2p10 is explicit enough that I trust it to correctly
reflect the intent.
Aug 31 '08 #23

P: n/a
On Sun, 31 Aug 2008 23:26:36 +0200, Harald van Dijk wrote:
VLAs aren't allowed as structure or union members. I can't find the
normative wording in the standard (references are appreciated),
Never mind. It's 6.7.2.1p8:
"A member of a structure or union may have any object type other than a
variably modified type."
Aug 31 '08 #24

P: n/a
On Sep 1, 12:31 am, Harald van Dk <true...@gmail.comwrote:
On Sun, 31 Aug 2008 23:26:36 +0200, Harald van Dk wrote:
[correcting me]
VLAs aren't allowed as structure or union members. I can't find the
normative wording in the standard (references are appreciated),

Never mind. It's 6.7.2.1p8:
"A member of a structure or union may have any object type other than a
variably modified type."

Ah yes. Thanks.
Aug 31 '08 #25

P: n/a
On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:

<snip>
But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types. For example:
Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.
Aug 31 '08 #26

P: n/a
James Tursa wrote:
But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types.
That's how the string functions work.

N869
7.21 String handling <string.h>
7.21.1 String function conventions
[#1] The header <string.hdeclares one type and several
functions, and defines one macro useful for manipulating
arrays of character type and other objects treated as arrays
of character type.
--
pete
Sep 1 '08 #27

P: n/a
On Sun, 31 Aug 2008 16:42:47 -0700 (PDT), vi******@gmail.com wrote:
>On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:

<snip>
>But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types. For example:

Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.
So is this conforming?

double d[2][3];
double *dp = (double *) d;
int i;
for( i=0; i<6; i++ )
dp = (double *)(((unsigned char *)dp) + sizeof(double));

James Tursa
Sep 1 '08 #28

P: n/a
On Sep 1, 3:37 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
On Sun, 31 Aug 2008 16:42:47 -0700 (PDT), vipps...@gmail.com wrote:
<snip>
Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.

So is this conforming?

double d[2][3];
double *dp = (double *) d;
int i;
for( i=0; i<6; i++ )
dp = (double *)(((unsigned char *)dp) + sizeof(double));
I don't know, but it's a good question; I'd like to know as well.

Sep 1 '08 #29

P: n/a
On Sep 1, 11:03*am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
I get the part about x[0][5] maybe not working.

But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types.
There is no special case for unsigned char
w.r.t bounds checking. You can't create
a pointer into an object, and then use that
pointer to access beyond the object's bounds,
regardless of the pointer type.

For example:
>
double d[2][3];
double *dp = (double *) d;
unsigned char *ucp = (unsigned char *) d;
double *xdp = malloc(sizeof(d));
unsigned char *xucp = malloc(sizeof(d));
mydoublecopy(xdp,dp,6); *// assume prototype present
myucharcopy(xucp,ucp,6*sizeof(double));

where

void mydoublecopy(double *t, double *s, size_t n) {
while( n-- ) { *t++ = *s++; } }

void myucharcopy(unsigned char *t, unsigned char *s, size_t n) {
while( n-- ) { *t++ = *s++; } }
Note that the expression "d" is defined to
mean &d[0], in a value context (which is what
we have here). That is, the address of an array
of three doubles.

'mydoublecopy' and 'myucharcopy' both cause
undefined behaviour because they try to access
beyond the bounds of this array.
Now, if you had written:
double *dp = (double *) &d;
unsigned char *ucp = (unsigned char *) &d;

then there would be no undefined behaviour,
because d is an object containing six doubles
(as opposed to d[0] which is an object
containing three doubles).
Sep 1 '08 #30

P: n/a
vi******@gmail.com wrote:
On Sep 1, 3:37 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
>On Sun, 31 Aug 2008 16:42:47 -0700 (PDT), vipps...@gmail.com wrote:
<snip>
>>Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.
So is this conforming?

double d[2][3];
double *dp = (double *) d;
int i;
for( i=0; i<6; i++ )
dp = (double *)(((unsigned char *)dp) + sizeof(double));

I don't know, but it's a good question; I'd like to know as well.
I think it's OK.
Any object pointer type can be converted
to a pointer to a character type
and the only problems that the standard says might be in the way
of converting a pointer to character type to another object pointer,
are alignment and space issues,
and those are both satisfied in this case.

--
pete
Sep 1 '08 #31

P: n/a
Old Wolf <ol*****@inspire.net.nzwrites:
On Sep 1, 11:03*am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
>I get the part about x[0][5] maybe not working.

But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types.

There is no special case for unsigned char
w.r.t bounds checking. You can't create
a pointer into an object, and then use that
pointer to access beyond the object's bounds,
regardless of the pointer type.

For example:
>>
double d[2][3];
double *dp = (double *) d;
unsigned char *ucp = (unsigned char *) d;
double *xdp = malloc(sizeof(d));
unsigned char *xucp = malloc(sizeof(d));
mydoublecopy(xdp,dp,6); *// assume prototype present
myucharcopy(xucp,ucp,6*sizeof(double));

where

void mydoublecopy(double *t, double *s, size_t n) {
while( n-- ) { *t++ = *s++; } }

void myucharcopy(unsigned char *t, unsigned char *s, size_t n) {
while( n-- ) { *t++ = *s++; } }

Note that the expression "d" is defined to
mean &d[0], in a value context (which is what
we have here). That is, the address of an array
of three doubles.

'mydoublecopy' and 'myucharcopy' both cause
undefined behaviour because they try to access
beyond the bounds of this array.
The reasoning seem wrong when you go down to 1D arrays. With double
d[2][3]; d is &d[0] and you are saying that this pointer can't be used
to access beyond that first element of d. But if I declare double
x[2]; I most certainly can use x (== &x[0]) to access beyond that
first element.

I think a case can be made that d[0][5] is undefined, but the case
must rest on something that is particular to 2D arrays or an except
must be made for 1D ones.
Now, if you had written:
double *dp = (double *) &d;
unsigned char *ucp = (unsigned char *) &d;

then there would be no undefined behaviour,
because d is an object containing six doubles
(as opposed to d[0] which is an object
containing three doubles).
People habitually pass a 1D array, x, to a function by writing x
rather than &x.

--
Ben.
Sep 1 '08 #32

P: n/a
James Tursa wrote:
On Sun, 31 Aug 2008 17:54:50 -0700 (PDT), Old Wolf
<ol*****@inspire.net.nzwrote:
>On Sep 1, 11:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
>>I get the part about x[0][5] maybe not working.

But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types.
There is no special case for unsigned char
w.r.t bounds checking. You can't create
a pointer into an object, and then use that
pointer to access beyond the object's bounds,
regardless of the pointer type.

Doesn't memcpy and the like do just that?
The entire two dimensional array is one object.
The type of an object depends on how it is accessed.
memcpy accesses its objects as arrays of unsigned char.

N869
6.3.2 Other operands
6.3.2.1 Lvalues and function designators
[#1]

When an object is said to have a particular
type, the type is specified by the lvalue used to designate
the object.
--
pete
Sep 1 '08 #33

P: n/a
vi******@gmail.com writes:
On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:

<snip>
>But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types. For example:

Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.
Slight correction: You can treat any *object* as an array of unsigned
char. Remember: arrays are not pointers, and pointers are not arrays.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 1 '08 #34

P: n/a
pete <pf*****@mindspring.comwrites:
James Tursa wrote:
>But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types.

That's how the string functions work.

N869
7.21 String handling <string.h>
7.21.1 String function conventions
[#1] The header <string.hdeclares one type and several
functions, and defines one macro useful for manipulating
arrays of character type and other objects treated as arrays
of character type.
The latter refers to the mem* functions (memcpy, memmove, memcmp,
memchr, memset). Though they're described in the "String handling"
section and declared in <string.h>, I wouldn't call them string
functions.

(The type is size_t, and the macro is NULL; both are also declared in
<stddef.hand other headers.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 1 '08 #35

P: n/a
On Sep 1, 5:54 am, Keith Thompson <ks...@mib.orgwrote:
vipps...@gmail.com writes:
On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
<snip>
But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types. For example:
Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.

Slight correction: You can treat any *object* as an array of unsigned
char. Remember: arrays are not pointers, and pointers are not arrays.
I don't think your correction is valid.
You're saying you can treat any object as an array of unsigned char.

int i = 123;
(unsigned char *)i[0] wouldn't be valid.

I said you can treat any pointer to object as an array of unsigned
char:

int i = 123;
*(unsigned char*)&i is valid.

Perhaps we are saying the same thing but you misunderstood me and I
misunderstood you?
Sep 1 '08 #36

P: n/a
On Sep 1, 5:59 am, vipps...@gmail.com wrote:
On Sep 1, 5:54 am, Keith Thompson <ks...@mib.orgwrote:
vipps...@gmail.com writes:
On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
<snip>
>But the only way I can make sense of everything else that everyone is
>trying to tell me is that there are special rules for unsigned char
>that prevent bounds checking for this type of code that don't apply to
>other types. For example:
Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.
Slight correction: You can treat any *object* as an array of unsigned
char. Remember: arrays are not pointers, and pointers are not arrays.

I don't think your correction is valid.
You're saying you can treat any object as an array of unsigned char.

int i = 123;
(unsigned char *)i[0] wouldn't be valid.
correction:
*(unsigned char *)i

Sep 1 '08 #37

P: n/a
James Tursa wrote:
On Fri, 29 Aug 2008 11:08:00 GMT, James Kuyper
<ja*********@verizon.netwrote:
>The key point is the pointer conversion. At the point where that
conversion occurs, the compiler knows that (double*)array == array[0].
It's undefined if any number greater than 1 is added to that pointer
value, and also if that pointer is dereferenced after adding 1 to it.

Trying to understand your answer as it relates to the original post. I
don't see how the original function gets an address 2 beyond the end,
or 1 beyond the end and attempts to dereference it, as you seem to be
saying. Can you point this out? Did I misunderstand you?
Quite possibly. The key point you need to understand is what array the
pointer points at. It's important to understand that, given the
following declaration:

double array[2][1];

"array" is not an array of "double". The element type for "array" is
"double[1]". On the other hand, array[0] is itself an array; the element
type for that array is "double".

The rules governing the behavior of pointer arithmetic are described by
6.5.6p8 in terms of an array whose element type is the type that the
pointer points at; they make no sense when interpreted in terms of an
array with any other element type.

The standard does NOT clearly state where it is that (double*)array
points. I will assume what everyone "knows", which is that it points at
the same location in memory as the original pointer.

There is only one array with an element type of "double" that starts at
that location. It isn't "array", it's "array[0]". Therefore, the rules
concerning pointer arithmetic are described relative to array[0]. Since
array[0] has a length of 1, the behavior is undefined if any integer
other than 0 or 1 is added to it, and it is not legal to dereference it
after 1 has been added to it; the same must also be true of (double*)array.
Sep 1 '08 #38

P: n/a
vi******@gmail.com writes:
On Sep 1, 5:54 am, Keith Thompson <ks...@mib.orgwrote:
>vipps...@gmail.com writes:
On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
<snip>
>But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types. For example:
Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.

Slight correction: You can treat any *object* as an array of unsigned
char. Remember: arrays are not pointers, and pointers are not arrays.

I don't think your correction is valid.
You're saying you can treat any object as an array of unsigned char.

int i = 123;
(unsigned char *)i[0] wouldn't be valid.
No, it wouldn't.

First, [] binds more tightly than the cast operator, so your
expression is equivalent to (unsigned char *)(i[0]), which doesn't
make much sense. Assuming you meant ((unsigned char*)i)[0], that's
*not* treating the object i as an array of unsigned char. It's
converting the value of i to a pointer value, and then applying the []
operator to that pointer value.
I said you can treat any pointer to object as an array of unsigned
char:

int i = 123;
*(unsigned char*)&i is valid.
Yes, that's valid. It's treating the object i as an array of unsigned
char.
Perhaps we are saying the same thing but you misunderstood me and I
misunderstood you?
We may be trying to say the same thing. I think you're just saying it
incorrectly.

You can't treat a pointer as an array (except that you can treat a
pointer object as an array of unsigned char, but that has nothing to
do with the fact that it's a pointer object). Arrays and pointers are
two entirely different things (though you need to use pointers to
access array elements).

Here's a concrete example:

#include <stdio.h>
int main(void)
{
int obj = 123;
unsigned char *ptr = (unsigned char*)&obj;
int i;
for (i = 0; i < sizeof obj; i ++) {
printf("ptr[i] = 0x%x\n", ptr[i]);
}
return 0;
}

This treats the object obj as if it were an array of unsigned char.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 1 '08 #39

P: n/a
vi******@gmail.com writes:
On Sep 1, 5:59 am, vipps...@gmail.com wrote:
>On Sep 1, 5:54 am, Keith Thompson <ks...@mib.orgwrote:
[...]
Slight correction: You can treat any *object* as an array of unsigned
char. Remember: arrays are not pointers, and pointers are not arrays.

I don't think your correction is valid.
You're saying you can treat any object as an array of unsigned char.

int i = 123;
(unsigned char *)i[0] wouldn't be valid.
correction:
*(unsigned char *)i
That wouldn't be valid either -- and it's also not treating the object
as an array of unsigned char. It's still converting the value of i to
a pointer.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 1 '08 #40

P: n/a
vi******@gmail.com wrote:
On Sep 1, 5:59 am, vipps...@gmail.com wrote:
>On Sep 1, 5:54 am, Keith Thompson <ks...@mib.orgwrote:
>>vipps...@gmail.com writes:
On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
<snip>
But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types. For example:
Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.
Slight correction: You can treat any *object* as an array of unsigned
char. Remember: arrays are not pointers, and pointers are not arrays.
I don't think your correction is valid.
You're saying you can treat any object as an array of unsigned char.
That doesn't mean that you can do it any way that you want to.
You access the members of an array,
through a pointer to the member type.

*(unsigned char *)&i
>int i = 123;
(unsigned char *)i[0] wouldn't be valid.
correction:
*(unsigned char *)i


--
pete
Sep 1 '08 #41

P: n/a
On Sep 1, 6:14 am, Keith Thompson <ks...@mib.orgwrote:
vipps...@gmail.com writes:
On Sep 1, 5:54 am, Keith Thompson <ks...@mib.orgwrote:
vipps...@gmail.com writes:
On Sep 1, 2:03 am, James Tursa <aclassyguywithakno...@hotmail.com>
wrote:
<snip>
But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types. For example:
Yes there is. Because you can treat any ptr to object as an array of
unsigned char, to observe the objects representation.
Slight correction: You can treat any *object* as an array of unsigned
char. Remember: arrays are not pointers, and pointers are not arrays.
I don't think your correction is valid.
You're saying you can treat any object as an array of unsigned char.
int i = 123;
(unsigned char *)i[0] wouldn't be valid.

No, it wouldn't.

First, [] binds more tightly than the cast operator, so your
expression is equivalent to (unsigned char *)(i[0]), which doesn't
make much sense. Assuming you meant ((unsigned char*)i)[0], that's
*not* treating the object i as an array of unsigned char. It's
converting the value of i to a pointer value, and then applying the []
operator to that pointer value.
Yes, that is what I meant, I corrected it in a follow-up.
I said you can treat any pointer to object as an array of unsigned
char:
int i = 123;
*(unsigned char*)&i is valid.

Yes, that's valid. It's treating the object i as an array of unsigned
char.
Perhaps we are saying the same thing but you misunderstood me and I
misunderstood you?

We may be trying to say the same thing. I think you're just saying it
incorrectly.
Indeed. :-)

<snip>
Here's a concrete example:

#include <stdio.h>
int main(void)
{
int obj = 123;
unsigned char *ptr = (unsigned char*)&obj;
int i;
for (i = 0; i < sizeof obj; i ++) {
printf("ptr[i] = 0x%x\n", ptr[i]);
}
return 0;

}
To be more concrete, I suggest size_t i; instead of int i; (with
INT_MAX < sizeof (int) your example is not concrete anymore, but
that's not likely)

Also, even if i is changed to size_t, if sizeof (int) == SIZE_MAX,
that would be an infinite loop...

....
size_t i;
for(printf("ptr[i] = 0x%x\n", ptr[i = 0]); i && i < sizeof obj; i++)
printf("ptr[i] = 0x%x\n", ptr[i]);
Anyway, thanks for clearing this up. I hope I'll remember this so I
won't use incorrect terminology in the future.
Sep 1 '08 #42

P: n/a
Keith Thompson wrote:
pete <pf*****@mindspring.comwrites:
>James Tursa wrote:
>>But the only way I can make sense of everything else that everyone is
trying to tell me is that there are special rules for unsigned char
that prevent bounds checking for this type of code that don't apply to
other types.
That's how the string functions work.

N869
7.21 String handling <string.h>
7.21.1 String function conventions
[#1] The header <string.hdeclares one type and several
functions, and defines one macro useful for manipulating
arrays of character type and other objects treated as arrays
of character type.

The latter refers to the mem* functions (memcpy, memmove, memcmp,
memchr, memset). Though they're described in the "String handling"
section and declared in <string.h>, I wouldn't call them string
functions.
Brian W. Kernighan and Dennis M. Ritchie
would call them string functions.

K&R2, Appendix B3:
There are two groups of string functions
defined in the header <string.h>.
The first have names begining with str;
the second have names begining with mem.

It's not only just me and the standard.

--
pete
Sep 1 '08 #43

P: n/a
James Tursa wrote:
....
OK, that's fine for objects, but that doesn't answer my question. What
is it about 2-dimensional (or multi-dimensional) arrays of double that
does not allow them to be stepped through with a double* ?
Ultimately, nothing more or less than the fact that the standard says
that the behavior is undefined. Because the behavior is undefined,
compilers are allowed to generate code that might fail if such stepping
is attempted (though this is rather unlikely). More importantly,
compilers are allowed to generate code that assumes that such stepping
will not be attempted, and therefore fails catastrophically if it
actually is attempted - the most plausible mode of failure is a failure
to check for aliasing.

Specific details:

Given

double array[2][1];
double *p = (double*)array;

If there is code which sets array[1][i] to one value, and p[j] to
another value, the compiler not required to consider the possibility
that p[j] and array[1][i] might point at the same location in memory.
It's allowed to keep either value in a register, or to keep the two
values in different registers. It's not required to make the next
reference to array[1][i] give the same value as the next reference to p[j].

This is because the behavior would be undefined if 'i' and 'j' had
values that might ordinarily cause you the expect array[1][i] and p[j]
to refer to the same location. Note: this convoluted wording is
necessary, because if 'i' and 'j' have such values, then at least one of
the two expressions has undefined behavior, rendering it meaningless to
talk about which location that expression actually refers to.

... And
ultimately, I would also ask if it is safe/conforming to use memcpy or
the like to copy values from/to such an array wholesale. e.g., is it
Yes, it is, and the reason is that the standard explicitly allows access
to entirely of an object through lvalues of "unsigned char", and the
behavior of memcpy() is defined in terms of operations on "unsigned
char" lvalues. There is no similar exemption for "double*".

Sep 1 '08 #44

P: n/a
vi******@gmail.com writes:
On Sep 1, 6:14 am, Keith Thompson <ks...@mib.orgwrote:
[...]
>Here's a concrete example:

#include <stdio.h>
int main(void)
{
int obj = 123;
unsigned char *ptr = (unsigned char*)&obj;
int i;
for (i = 0; i < sizeof obj; i ++) {
printf("ptr[i] = 0x%x\n", ptr[i]);
}
return 0;

}

To be more concrete, I suggest size_t i; instead of int i; (with
INT_MAX < sizeof (int) your example is not concrete anymore, but
that's not likely)

Also, even if i is changed to size_t, if sizeof (int) == SIZE_MAX,
that would be an infinite loop...
Agreed, size_t is a little better here than int -- not because of any
real risk of that sizeof(int) will equal or exceed either SIZE_MAX or
INT_MAX, but just because sizeof yields a result of type size_t, and
it's usually better to use consistent types unless you have a good
reason not to.

On the other hand, it's not entirely unreasonable to use int for
quantities that you can be sure won't exceed 32767.
...
size_t i;
for(printf("ptr[i] = 0x%x\n", ptr[i = 0]); i && i < sizeof obj; i++)
printf("ptr[i] = 0x%x\n", ptr[i]);
That's not *quite* convoluted enough for the IOCCC, but keep at it.
8-)}

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 1 '08 #45

P: n/a
pete <pf*****@mindspring.comwrites:
Keith Thompson wrote:
>pete <pf*****@mindspring.comwrites:
[...]
>>That's how the string functions work.

N869
7.21 String handling <string.h>
7.21.1 String function conventions
[#1] The header <string.hdeclares one type and several
functions, and defines one macro useful for manipulating
arrays of character type and other objects treated as arrays
of character type.
The latter refers to the mem* functions (memcpy, memmove, memcmp,
memchr, memset). Though they're described in the "String handling"
section and declared in <string.h>, I wouldn't call them string
functions.

Brian W. Kernighan and Dennis M. Ritchie
would call them string functions.

K&R2, Appendix B3:
There are two groups of string functions
defined in the header <string.h>.
The first have names begining with str;
the second have names begining with mem.

It's not only just me and the standard.
Ok, then I disagree with you *and* the standard *and* Kernighan *and*
Ritchie. Except that I generally accept the standard's definitions
for terms, whether I think they're sensible or not, for the sake
of consistent communication.

On the other hand, though the standard does use the term "string
functions", it doesn't actually define it. It does, however, provide
definitions for "string" and "function" -- and memcpy, for example, is
a function that doesn't have anything directly to do with strings.

oh, well.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Sep 1 '08 #46

P: n/a

OK. I have learned three things today based on everyone's posts:

1)
double d[2][3];
double *dp = malloc(sizeof(d));
memcpy(dp,d,sizeof(d));

This is conforming because memcpy accesses the elements as an unsigned
char array and the standard guarantees this will work ...

OR

it is not conforming because I am requesting access to memory beyond
the d[0] array inside memcpy and there are no special rules in the
standard that guarantee this will work. I need to use &d instead.

2)
double d[2][3];
double *dp = (double *) d;
int i;
for( i=0; i<6; i++ )
dp = (double *)(((unsigned char *)dp) + sizeof(double));

This is conforming because I am generating addresses using unsigned
char and am not calculating/dereferencing an address beyond the end of
d so the standard guarantees this will work ...

OR

it is not conforming because I am generating an address beyond the
d[0] array partway into the loop and there are no special rules in the
standard that guarantee this will work. I need to use &d instead when
defining dp.

3)
unsigned char uc[1];
unsigned char *ucp = (unsigned char *) uc;
unsigned char c, d;
uc[0] = 'a';
c = uc[0]; // (1)
ucp[0] = 'b'; // (2)
d = uc[0]; // (3)

This is conforming because the standard guarantees I can access the
elements of uc through the unsigned char pointer ucp and get
predictable results ...

OR

it is not conforming because the compiler is free to optimize and hold
the uc[0] value in (1) in a register or cache for later use in (3)
without checking to see if it was changed in (2).The value of d is
undefined.
I have a headache ... I'm going to bed ...

James Tursa
Sep 1 '08 #47

P: n/a
James Tursa said:
>
OK. I have learned three things today based on everyone's posts:

1)
double d[2][3];
double *dp = malloc(sizeof(d));
memcpy(dp,d,sizeof(d));

This is conforming because memcpy accesses the elements as an unsigned
char array and the standard guarantees this will work ...
....unless malloc fails and returns NULL, which it might.

As for the rest of it, I wouldn't want to trust my weight to an iteration
through that copy.

(I must confess that I don't see the fascination with deliberately
confusing type issues, though. If I want a one-dimensional array, I'll
build one. If I want a two-dimensional array, I'll build one of those
instead. Why mix them up?)

<snip>

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 1 '08 #48

P: n/a
On Mon, 01 Sep 2008 08:02:29 +0000, Richard Heathfield
<rj*@see.sig.invalidwrote:
>
(I must confess that I don't see the fascination with deliberately
confusing type issues, though. If I want a one-dimensional array, I'll
build one. If I want a two-dimensional array, I'll build one of those
instead. Why mix them up?)
Because I want to copy a C 2-dimensional array (or multi-dimensional
array) to a MATLAB mxArray data pointer in a conforming way. Sounds
simple enough. Just copy the contents of a 2-dimensional array to a
data area accessed through a double *. The MATLAB functions will give
me a double * for the target data area and I have assumed (apparently
incorrectly) that a simple memcpy using the C variable name is
conforming. Apparently (according to some) I need to use &name instead
of just name to be conforming.

I'm just trying to understand the rules. I'm not trying to make up
deliberately confusing type issues. But as you can see I am getting
two different answers to many fairly simple questions (at least I
thought they were simple at the outset).

James Tursa
Sep 1 '08 #49

P: n/a
James Tursa said:
On Mon, 01 Sep 2008 08:02:29 +0000, Richard Heathfield
<rj*@see.sig.invalidwrote:
>>
(I must confess that I don't see the fascination with deliberately
confusing type issues, though. If I want a one-dimensional array, I'll
build one. If I want a two-dimensional array, I'll build one of those
instead. Why mix them up?)

Because I want to copy a C 2-dimensional array (or multi-dimensional
array) to a MATLAB mxArray data pointer in a conforming way. Sounds
simple enough. Just copy the contents of a 2-dimensional array to a
data area accessed through a double *. The MATLAB functions will give
me a double * for the target data area and I have assumed (apparently
incorrectly) that a simple memcpy using the C variable name is
conforming. Apparently (according to some) I need to use &name instead
of just name to be conforming.
If all you want is a solution that is guaranteed not to break any rules,
it's pretty easy. If MATLAB provides a space into which you need only copy
the data, you can do so in a simple loop:

/* We assume that arr is defined as double arr[ROWS][COLS]. We
further assume that p is of type double *, and points to
space at least ROWS * COLS * sizeof(double) bytes in size.
*/
t = p;
thisrow = 0;
while(thisrow < ROWS)
{
memcpy(t, arr[thisrow], sizeof arr[thisrow]);
t += COLS; /* move t on by COLS doubles */
++thisrow;
}

(If MATLAB wants you to provide the space and tell it where to look, then
you allocate a big enough space: p = malloc(ROWS * COLS * sizeof *p), and,
provided that the allocation was successful, copy the array into it as
shown above. Then tell MATLAB about p.)

I'm not saying this is the fastest way to do it, but I think it's the
fastest way that is guaranteed not to break any rules!

HTH. HAND.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
"Usenet is a strange place" - dmr 29 July 1999
Sep 1 '08 #50

152 Replies

This discussion thread is closed

Replies have been disabled for this discussion.