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

Array assignment via struct

P: n/a
Hi!

I'm working on automatically generated code, and need to assign arrays.
memcpy is an obvious solution, but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.
Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

free(a);
free(b);
return 0;
}

I wouldn't have tought that this would compile, let alone not give a
single warning (gcc -W -Wall -pedantic). It even works :-), as I tried
copying and displaying a string. I can easily code that in my code
generator (a translator, actually) and I suppose it would even let me
cast expressions to an array!

What I'm wondering, since this is not too bad looking as a solution,
is:
1) Is this solution common?
2) Is this portable?
3) Does this actually respects the C standard? (if not, why?)
4) Any way to improve this assign without using a function?

FYI, I tried using anonymous structures:
*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
t[10];}*) b);
but the compiler complained about incompatible types, which I
understand the cause. I had to try it, though.

Thanks
--
Eric Laberge

Nov 15 '05 #1
Share this Question
Share on Google+
36 Replies


P: n/a
In article <11*********************@g47g2000cwa.googlegroups. com>,
Eric Laberge <de********@myrealbox.com> wrote:

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

What I'm wondering, since this is not too bad looking as a solution,
is:
1) Is this solution common?
Casting void pointers to struct pointers is *very* common indeed; however,
declaring a new struct in the middle of a statement...that part is unusual.
2) Is this portable?
I think so. I tried it on three completely independent
compilers and they all accepted it in c89 and c99 modes.
3) Does this actually respects the C standard? (if not, why?)
Dunno. Hopefully someone more fluent with the standard(s) can
indicate whether it is conforming and to what level (and
restore my confidence in my three favorite compilers!).
4) Any way to improve this assign without using a function?


The last time I had to move small chunks of data of size unknown-by-me
but knowable-by-the-program, I had a menu of different ways to handle it:

* Small items of 1, 2, 4, or 8 bytes were cast to built-in types of
the appropriate size (e.g. char thru double).
* Odd sized things, misaligned data, and larger objects were just passed
to memcpy().
* Overlapping data of course gets memmove().

Doing a struct copy in the source code might map to a memcpy (or worse,
memmove) in the binary anyway. You'll have to examine the assembly
output and maybe even profile the code to get a handle on what's
optimal (which seems to be the subtext of your wanting to avoid
memcpy).

Declaring a struct in the middle of doing something else is
at least visually jarring. I'd probably move the struct
declaration up and out, or at least replace the statement
in place with

do {
struct copy {unsigned char t[10];};
*((struct copy *) a) = *((struct copy*) b);
} while (0)

and maybe skip the do while(0) stuff it's straight-line generated
code, but assign unique names to the structs.
--
7842++
Nov 15 '05 #2

P: n/a
On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
I'm working on automatically generated code, and need to assign arrays.
memcpy is an obvious solution, but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.
Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

free(a);
free(b);
return 0;
}


<snip>

The only problem I can see is that the structure is not necessarily
the same size as the array - the compiler is free to add padding to the
structure.

Better to declare the structure first and do sizeof on it to check.

Not really portable because on different platforms different amounts of
padding may be added. Memcpy is probably simpler.

Nov 15 '05 #3

P: n/a
Netocrat wrote:

On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
I'm working on automatically generated code,
and need to assign arrays.
memcpy is an obvious solution,
but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.
Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10);
/* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

free(a);
free(b);
return 0;
}


<snip>

The only problem I can see is that the structure is not necessarily
the same size as the array
- the compiler is free to add padding to the structure.

Better to declare the structure first and do sizeof on it to check.


Use sizeof structure for the argument in the call to malloc.

/* BEGIN new.c */

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

struct copy {
unsigned char t[10];
};

int main(void)
{
void *a = malloc(sizeof(struct copy));
void *b = malloc(sizeof(struct copy));

if (a == NULL || b == NULL) {
puts("malloc problem");
exit(EXIT_FAILURE);
}
strcpy(b, "123456789");
*(struct copy *)a = *(struct copy *)b;
free(b);
puts(a);
free(a);
return 0;
}

/* END new.c */
--
pete
Nov 15 '05 #4

P: n/a
On Fri, 05 Aug 2005 02:18:18 +0000, pete wrote:
Netocrat wrote:

On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
> I'm working on automatically generated code,
> and need to assign arrays.
> memcpy is an obvious solution,
> but it becomes complicated to use in the
> context I'm working on, ie.: I could use it but I don't want to.
> Arrays cannot be assigned in C, but structs can, so I coded the
> following:
>
> #include <stdlib.h>
>
> int main(void)
> {
> void* a = malloc(10);
> /* This obviously should be checked for malloc
> failure */
> void* b = malloc(10); /* This too... */
>
> *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
>
> free(a);
> free(b);
> return 0;
> }
<snip>

The only problem I can see is that the structure is not necessarily
the same size as the array
- the compiler is free to add padding to the structure.

Better to declare the structure first and do sizeof on it to check.


Use sizeof structure for the argument in the call to malloc.

Additions untested; for comment value only...
/* BEGIN new.c */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define ARRSIZE 10
struct copy {
unsigned char t[ARRSIZE];
};

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

if (sizeof(struct copy) > ARRSIZE) {
/* do you want to have to potentially deal with this
* complication? Is it even an issue? */
}
a = malloc(sizeof(struct copy));
b = malloc(sizeof(struct copy));

if (a == NULL || b == NULL) {
puts("malloc problem");
exit(EXIT_FAILURE);
}
strcpy(b, "123456789");
*(struct copy *)a = *(struct copy *)b; free(b); puts(a); free(a);
return 0;
}
}
/* END new.c */

Nov 15 '05 #5

P: n/a

Netocrat wrote:
On Fri, 05 Aug 2005 02:18:18 +0000, pete wrote:
Netocrat wrote:

On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:

> I'm working on automatically generated code,
> and need to assign arrays.
> memcpy is an obvious solution,
> but it becomes complicated to use in the
> context I'm working on, ie.: I could use it but I don't want to.
> Arrays cannot be assigned in C, but structs can, so I coded the
> following:
>
> #include <stdlib.h>
>
> int main(void)
> {
> void* a = malloc(10);
> /* This obviously should be checked for malloc
> failure */
> void* b = malloc(10); /* This too... */
>
> *((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
>
> free(a);
> free(b);
> return 0;
> }

<snip>

The only problem I can see is that the structure is not necessarily
the same size as the array
- the compiler is free to add padding to the structure.

Better to declare the structure first and do sizeof on it to check.
Use sizeof structure for the argument in the call to malloc.

Additions untested; for comment value only...
/* BEGIN new.c */

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


#define ARRSIZE 10
struct copy {
unsigned char t[ARRSIZE];
};

int main(void)
{

void *a, b;


Is this really what you want? Typo, I presume. So, we'll change it
to...
void *a, *b;
and the rest follows.
if (sizeof(struct copy) > ARRSIZE) {
/* do you want to have to potentially deal with this
* complication? Is it even an issue? */
}
a = malloc(sizeof(struct copy));
b = malloc(sizeof(struct copy));

if (a == NULL || b == NULL) {
puts("malloc problem");
exit(EXIT_FAILURE);
}
strcpy(b, "123456789");
*(struct copy *)a = *(struct copy *)b; free(b); puts(a); free(a);
return 0;
}
}
/* END new.c */


Nov 15 '05 #6

P: n/a
On Thu, 04 Aug 2005 21:34:47 -0700, Suman wrote:
Netocrat wrote:
On Fri, 05 Aug 2005 02:18:18 +0000, pete wrote: <snip>
> int main(void)
> {

void *a, b;


Is this really what you want? Typo, I presume. So, we'll change it
to...
void *a, *b;


Yep, typo, well caught.

Nov 15 '05 #7

P: n/a
On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:
Hi!

I'm working on automatically generated code, and need to assign arrays.
memcpy is an obvious solution, but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.
It is difficult to see how it would be more complicated than what you have
here.
Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
memcpy(a, b, 10);
free(a);
free(b);
return 0;
}

I wouldn't have tought that this would compile, let alone not give a
single warning (gcc -W -Wall -pedantic). It even works :-), as I tried
copying and displaying a string. I can easily code that in my code
generator (a translator, actually) and I suppose it would even let me
cast expressions to an array!
You can't cast to an array type.
What I'm wondering, since this is not too bad looking as a solution,
is:
1) Is this solution common?
Not in my experience. :-)
2) Is this portable?
It probably works on a wide range of implementations.
3) Does this actually respects the C standard? (if not, why?)
You're trying to access an array as a structure which ultimately has
undefined behaviour. The fact that malloc'd memory is used muddies the
water a bit especially in C90. But C99's concept of effective type makes
it clearer.
4) Any way to improve this assign without using a function?

FYI, I tried using anonymous structures:
*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
t[10];}*) b);
but the compiler complained about incompatible types, which I
understand the cause. I had to try it, though.


What's the problem with using memcpy()?

Lawrence
Nov 15 '05 #8

P: n/a
Lawrence Kirby wrote:
On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:

Hi!

I'm working on automatically generated code, and need to assign arrays.
memcpy is an obvious solution, but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.

It is difficult to see how it would be more complicated than what you have
here.

Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

memcpy(a, b, 10);

free(a);
free(b);
return 0;
}

I wouldn't have tought that this would compile, let alone not give a
single warning (gcc -W -Wall -pedantic). It even works :-), as I tried
copying and displaying a string. I can easily code that in my code
generator (a translator, actually) and I suppose it would even let me
cast expressions to an array!

You can't cast to an array type.

What I'm wondering, since this is not too bad looking as a solution,
is:
1) Is this solution common?

Not in my experience. :-)

2) Is this portable?

It probably works on a wide range of implementations.

3) Does this actually respects the C standard? (if not, why?)

You're trying to access an array as a structure which ultimately has
undefined behaviour. The fact that malloc'd memory is used muddies the
water a bit especially in C90. But C99's concept of effective type makes
it clearer.

4) Any way to improve this assign without using a function?

FYI, I tried using anonymous structures:
*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
t[10];}*) b);
but the compiler complained about incompatible types, which I
understand the cause. I had to try it, though.

What's the problem with using memcpy()?

Lawrence

/* Assign array via struct */

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

#define LEN 20

typedef struct {
char a[LEN];
} S;

int main(void) {
S sa;
char A[LEN];

S *ps = malloc(LEN);
char *pa = malloc(LEN);

strcpy(sa.a, "Joe Wright Rocks");
puts(sa.a);

*(S*)A = sa;
puts(A);

strcpy(ps->a, A);
puts(ps->a);

*(S*)pa = *ps;
puts(pa);

return 0;
}

I love this language. :-)

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #9

P: n/a
On Fri, 05 Aug 2005 16:24:25 -0400, Joe Wright <jw*****@comcast.net>
wrote in comp.lang.c:
Lawrence Kirby wrote:
On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:

Hi!

I'm working on automatically generated code, and need to assign arrays.
memcpy is an obvious solution, but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.

It is difficult to see how it would be more complicated than what you have
here.

Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

memcpy(a, b, 10);

free(a);
free(b);
return 0;
}

I wouldn't have tought that this would compile, let alone not give a
single warning (gcc -W -Wall -pedantic). It even works :-), as I tried
copying and displaying a string. I can easily code that in my code
generator (a translator, actually) and I suppose it would even let me
cast expressions to an array!

You can't cast to an array type.

What I'm wondering, since this is not too bad looking as a solution,
is:
1) Is this solution common?

Not in my experience. :-)

2) Is this portable?

It probably works on a wide range of implementations.

3) Does this actually respects the C standard? (if not, why?)

You're trying to access an array as a structure which ultimately has
undefined behaviour. The fact that malloc'd memory is used muddies the
water a bit especially in C90. But C99's concept of effective type makes
it clearer.

4) Any way to improve this assign without using a function?

FYI, I tried using anonymous structures:
*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
t[10];}*) b);
but the compiler complained about incompatible types, which I
understand the cause. I had to try it, though.

What's the problem with using memcpy()?

Lawrence

/* Assign array via struct */

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

#define LEN 20

typedef struct {
char a[LEN];
} S;

int main(void) {
S sa;
char A[LEN];

S *ps = malloc(LEN);
char *pa = malloc(LEN);

strcpy(sa.a, "Joe Wright Rocks");
puts(sa.a);

*(S*)A = sa;


Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes
that A is, causing some sort of trap on some platforms, or possible
misaligned data or overwriting the destination array.
puts(A);

strcpy(ps->a, A);
puts(ps->a);

*(S*)pa = *ps;
puts(pa);

return 0;
}

I love this language. :-)


I strongly dislike people who write code like this. Especially if I
have to clean up after the 'clever' programmer. It would never pass a
code inspection at any shop with decent standards. Shops that don't
do code inspections don't have decent standards by definition.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 15 '05 #10

P: n/a

Jack Klein wrote:
<snip>
/* Assign array via struct */

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

#define LEN 20

typedef struct {
char a[LEN];
} S;

int main(void) {
S sa;
char A[LEN];

S *ps = malloc(LEN);
char *pa = malloc(LEN);

strcpy(sa.a, "Joe Wright Rocks");
puts(sa.a);

*(S*)A = sa;


Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes


Even if A is dynamically allocated, e.g. variable 'pa', does standard
guarantee that A is suitably aligned for struct S?
may I have C&V for that?

Krishanu

Nov 15 '05 #11

P: n/a
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:

Jack Klein wrote:
<snip>
> /* Assign array via struct */
>
> #include <stdio.h>
> #include <string.h>
> #include <stdlib.h>
>
> #define LEN 20
>
> typedef struct {
> char a[LEN];
> } S;
>
> int main(void) {
> S sa;
> char A[LEN];
>
> S *ps = malloc(LEN);
It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
to use sizeof(S) than LEN.
> char *pa = malloc(LEN);
>
> strcpy(sa.a, "Joe Wright Rocks");
> puts(sa.a);
>
> *(S*)A = sa;

Here you are potentially copying and assigning more than the allocated
(to src and dest) LEN bytes. A compiler might do this for performance
reasons. It's probably unlikely and a little pedantic but the point is
that what you're doing isn't guaranteed safe by the standard.

Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes

Given that element a must be located at the start of struct S, and that it
is a char array of size LEN, it's hard to see how it could be aligned
differently to the char array A of size LEN. Are you referring to this
specific case or in general? If this case, could you explain how the
standard allows the alignments to be different?
Even if A is dynamically allocated, e.g. variable 'pa', does standard
guarantee that A is suitably aligned for struct S?
It does. From the C89 draft (ANSI numbering):

4.10.3 Memory management functions

The pointer returned [by the calloc , malloc , and realloc functions] if
the allocation succeeds is suitably aligned so that it may be assigned to
a pointer to any type of object and then used to access such an object in
the space allocated ...
may I have C&V for that?


There is no constraint violation if that's what you mean.

--
No longer posting under real email address
(because that'll remove it from the spammers' databases)
Remove the first word of the domain to re-construct it.
Nov 15 '05 #12

P: n/a

Netocrat wrote:

<snip>
Even if A is dynamically allocated, e.g. variable 'pa', does standard
guarantee that A is suitably aligned for struct S?


It does. From the C89 draft (ANSI numbering):

4.10.3 Memory management functions

The pointer returned [by the calloc , malloc , and realloc functions] if
the allocation succeeds is suitably aligned so that it may be assigned to
a pointer to any type of object and then used to access such an object in
the space allocated ...
may I have C&V for that?


There is no constraint violation if that's what you mean.


This is exactly I am looking for, thanks.

Krishanu

Nov 15 '05 #13

P: n/a
Jack Klein wrote:
On Fri, 05 Aug 2005 16:24:25 -0400, Joe Wright <jw*****@comcast.net>
wrote in comp.lang.c:

Lawrence Kirby wrote:
On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:

Hi!

I'm working on automatically generated code, and need to assign arrays.
memcpy is an obvious solution, but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.
It is difficult to see how it would be more complicated than what you have
here.

Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);
memcpy(a, b, 10);

free(a);
free(b);
return 0;
}

I wouldn't have tought that this would compile, let alone not give a
single warning (gcc -W -Wall -pedantic). It even works :-), as I tried
copying and displaying a string. I can easily code that in my code
generator (a translator, actually) and I suppose it would even let me
cast expressions to an array!
You can't cast to an array type.

What I'm wondering, since this is not too bad looking as a solution,
is:
1) Is this solution common?
Not in my experience. :-)

2) Is this portable?
It probably works on a wide range of implementations.

3) Does this actually respects the C standard? (if not, why?)
You're trying to access an array as a structure which ultimately has
undefined behaviour. The fact that malloc'd memory is used muddies the
water a bit especially in C90. But C99's concept of effective type makes
it clearer.

4) Any way to improve this assign without using a function?

FYI, I tried using anonymous structures:
*((struct {unsigned char t[10];}*) a) = *((struct {unsigned char
t[10];}*) b);
but the compiler complained about incompatible types, which I
understand the cause. I had to try it, though.
What's the problem with using memcpy()?

Lawrence
/* Assign array via struct */

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

#define LEN 20

typedef struct {
char a[LEN];
} S;

int main(void) {
S sa;
char A[LEN];

S *ps = malloc(LEN);
char *pa = malloc(LEN);

strcpy(sa.a, "Joe Wright Rocks");
puts(sa.a);

*(S*)A = sa;

Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes
that A is, causing some sort of trap on some platforms, or possible
misaligned data or overwriting the destination array.

All of S is an array of char. What alignment requirements might there be
for an S? None. Structures don't have alignment requirements, their
members do. What are the alignment requirements of a char array?
puts(A);

strcpy(ps->a, A);
puts(ps->a);

*(S*)pa = *ps;
puts(pa);

return 0;
}

I love this language. :-)

I strongly dislike people who write code like this. Especially if I
have to clean up after the 'clever' programmer. It would never pass a
code inspection at any shop with decent standards. Shops that don't
do code inspections don't have decent standards by definition.

You 'strongly dislike people' who try to get 'clever' with C in a
newsgroup posting? Boy, are you tough.

I thought you'd get me for not checking the malloc() returns and not
free()ing ps and pa before exit. You never know your luck.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #14

P: n/a
Netocrat wrote:
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:

Jack Klein wrote:
<snip>
/* Assign array via struct */

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

#define LEN 20

typedef struct {
char a[LEN];
} S;

int main(void) {
S sa;
char A[LEN];

S *ps = malloc(LEN);

It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
to use sizeof(S) than LEN.
What padding could there be? S is essentially a char array. char *pa = malloc(LEN);

strcpy(sa.a, "Joe Wright Rocks");
puts(sa.a);

*(S*)A = sa;

Here you are potentially copying and assigning more than the allocated
(to src and dest) LEN bytes. A compiler might do this for performance
reasons. It's probably unlikely and a little pedantic but the point is
that what you're doing isn't guaranteed safe by the standard.
You're assuming sizeof sa might be greater than LEN. Why?Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes


Given that element a must be located at the start of struct S, and that it
is a char array of size LEN, it's hard to see how it could be aligned
differently to the char array A of size LEN. Are you referring to this
specific case or in general? If this case, could you explain how the
standard allows the alignments to be different?

Now you are on my side. Welcome home.
Even if A is dynamically allocated, e.g. variable 'pa', does standard
guarantee that A is suitably aligned for struct S?

It does. From the C89 draft (ANSI numbering):

4.10.3 Memory management functions

The pointer returned [by the calloc , malloc , and realloc functions] if
the allocation succeeds is suitably aligned so that it may be assigned to
a pointer to any type of object and then used to access such an object in
the space allocated ...

may I have C&V for that?

There is no constraint violation if that's what you mean.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #15

P: n/a
On Sat, 06 Aug 2005 08:45:05 -0400, Joe Wright wrote:
Netocrat wrote:
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:
Jack Klein wrote:
<snip>

>/* Assign array via struct */
>
>#include <stdio.h>
>#include <string.h>
>#include <stdlib.h>
>
>#define LEN 20
>
>typedef struct {
> char a[LEN];
>} S;
>
>int main(void) {
> S sa;
> char A[LEN];
>
> S *ps = malloc(LEN);

It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
to use sizeof(S) than LEN.

What padding could there be? S is essentially a char array.


Yeah, that's why I called it a pedantic point later in the post. Probably
the DS9000 is the only implementation to include padding. Anyhow you lose
nothing by using sizeof(S) instead of LEN and you are assured of
compliance.
> char *pa = malloc(LEN);
>
> strcpy(sa.a, "Joe Wright Rocks");
> puts(sa.a...);
>
> *(S*)A = sa;

Here you are potentially copying and assigning more than the allocated
(to src and dest) LEN bytes. A compiler might do this for performance
reasons. It's probably unlikely and a little pedantic but the point is
that what you're doing isn't guaranteed safe by the standard.

You're assuming sizeof sa might be greater than LEN. Why?


As above - padding. I wrote that it might be added for performance
reasons. I don't know if such reasons legitimately exist on a real-world
implementation (I can contrive a far-fetched hypothetical implementation
where they do), but you never know what code an optimising compiler is
going to generate.

<snip rest>

Nov 15 '05 #16

P: n/a
Lawrence Kirby <lk****@netactive.co.uk> wrote:
On Thu, 04 Aug 2005 15:41:10 -0700, Eric Laberge wrote:


[snip]
#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);


memcpy(a, b, 10);
free(a);
free(b);
return 0;
}
[snip] 3) Does this actually respects the C standard? (if not, why?)


You're trying to access an array as a structure which ultimately has
undefined behaviour. The fact that malloc'd memory is used muddies the
water a bit especially in C90. But C99's concept of effective type makes
it clearer.


Taking size and allignment issues away, I thing the array (supposing
it is an array type object already) *could* be accessed through
the struct type:

n869.txt, 6.5#7:
# [#7] An object shall have its stored value accessed only by
# an lvalue expression that has one of the following types:63)
[...]
# -- an aggregate or union type that includes one of the
# aforementioned types among its members (including,
# recursively, a member of a subaggregate or contained
# union), or

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #17

P: n/a
Netocrat <ne******@membersat.dodo.com.au> wrote:
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:
Jack Klein wrote:
<snip>
> /* Assign array via struct */
>
> #include <stdio.h>
> #include <string.h>
> #include <stdlib.h>
>
> #define LEN 20
>
> typedef struct {
> char a[LEN];
> } S;
>
> int main(void) {
> S sa;
> char A[LEN];
>
> S *ps = malloc(LEN);
It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
to use sizeof(S) than LEN.
char *pa = malloc(LEN);
>
> strcpy(sa.a, "Joe Wright Rocks");
> puts(sa.a);
>
> *(S*)A = sa; [snip] Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes


Given that element a must be located at the start of struct S, and that it
is a char array of size LEN, it's hard to see how it could be aligned
differently to the char array A of size LEN. Are you referring to this
specific case or in general? If this case, could you explain how the
standard allows the alignments to be different?


Type `char' has no alignment (ie. alignment(char) == 1), of course,
but at issue is not `char', but rather `char[10]'. Long time ago
(don't ask me for details now) I read that on DEC stations character
arrays in structs could have different alignments depending on their
size, so for example `char[15]' could have different alignment than
`char[31]'. All this was for purpose of memory access speed; ordinarily
`char[ANY]' doesn't have alignment (at least when ANY is a prime number,
for others I don't know), but when in a struct, a compiler
could assume that the array is positioned at a "fast" location and
generate more optimal code. (BTW, the discussion in which I read it
was about why struct-hack didn't work.)

I think that does it for an explanation of the struct alignment and
padding (later in this thread).
[snip] may I have C&V for that?


There is no constraint violation if that's what you mean.


He meant "Chapter & Verse". :-D

--
Stan Tobias
mailx `echo si***@FamOuS.BedBuG.pAlS.INVALID | sed s/[[:upper:]]//g`
Nov 15 '05 #18

P: n/a
"Eric Laberge" <de********@myrealbox.com> writes:
Hi!

I'm working on automatically generated code, and need to assign arrays.
memcpy is an obvious solution, but it becomes complicated to use in the
context I'm working on, ie.: I could use it but I don't want to.
Arrays cannot be assigned in C, but structs can, so I coded the
following:

#include <stdlib.h>

int main(void)
{
void* a = malloc(10); /* This obviously should be checked for malloc
failure */
void* b = malloc(10); /* This too... */

*((struct copy {unsigned char t[10];}*) a) = *((struct copy*) b);

free(a);
free(b);
return 0;
}


Perhaps it would be easier have the variables be
the assignable type to begin with:

#include <stdlib.h>

typedef struct { char v[10]; } SC_10;

int main(void)
{
SC_10 *a = malloc( sizeof *a );
SC_10 *b = malloc( sizeof *b );

if( !a || !b ){ ... }

sprintf( b->v, "Hi there\n" ); /* array use */

*a = *b; /* assignment use */

free(a);
free(b);
return 0;
}

No questionable behavior, and no casting necessary.

The type could be a union rather than a struct if
the "wrapped" value needs to be accessed as some
other type(s) in addition to being accessed as a
character array or unsigned character array.

If you can, it's almost always better to write
code so it doesn't need casts -- even code that
is automatically generated.

Nov 15 '05 #19

P: n/a
Joe Wright <jw*****@comcast.net> writes:
All of S is an array of char. What alignment requirements
might there be for an S? None. Structures don't have
alignment requirements, their members do. What are the
alignment requirements of a char array?


Structures can have alignment requirements that
are different from those of their members, and
here's a possible reason why they would.

On platforms where a 'char *' is a different
format and/or wider than an 'int *', an
implementation might choose to make all structs
be 'int' aligned, so that structure pointers
would be easier to deal with.

So a structure holding a character array would
still need 'int' alignment, even though the
contained character array would need only 'char'
alignment.

The alignment requirement also implies a sizing
requirement, since alignment_of(T) must evenly
divide 'sizeof(T)'. That's why a struct that
holds only a character array might be bigger
than the character array it holds.
Nov 15 '05 #20

P: n/a
On Sat, 06 Aug 2005 17:08:29 +0000, S.Tobias wrote:
Netocrat <ne******@membersat.dodo.com.au> wrote:
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:
Jack Klein wrote: <snip>
> /* Assign array via struct */
>
> #include <stdio.h>
> #include <string.h>
> #include <stdlib.h>
>
> #define LEN 20
>
> typedef struct {
> char a[LEN];
> } S;
>
> int main(void) {
> S sa;
> char A[LEN];
>
> S *ps = malloc(LEN);
It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
to use sizeof(S) than LEN.
> char *pa = malloc(LEN);
>
> strcpy(sa.a, "Joe Wright Rocks");
> puts(sa.a);
>
> *(S*)A = sa; [snip] Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes
that A is, causing some sort of trap on some platforms, or possible
misaligned data or overwriting the destination array. <snipped two lines above restored>

Given that element a must be located at the start of struct S, and that it
is a char array of size LEN, it's hard to see how it could be aligned
differently to the char array A of size LEN. Are you referring to this
specific case or in general? If this case, could you explain how the
standard allows the alignments to be different?


Type `char' has no alignment (ie. alignment(char) == 1), of course,
but at issue is not `char', but rather `char[10]'. Long time ago


Actually Joe's code #define's LEN to 20, you're thinking of the OP.
(don't ask me for details now) I read that on DEC stations character
arrays in structs could have different alignments depending on their
size, so for example `char[15]' could have different alignment than
`char[31]'. All this was for purpose of memory access speed; ordinarily
`char[ANY]' doesn't have alignment (at least when ANY is a prime number,
for others I don't know), but when in a struct, a compiler
could assume that the array is positioned at a "fast" location and
generate more optimal code. (BTW, the discussion in which I read it
was about why struct-hack didn't work.)


Well you've confirmed that it's not merely hypothetical - padding
actually is added in some real-world implementations. So to expand on
Jack's explanation of specific code being generated, perhaps something
like this:

4 padding bytes are added after the array of 20 char in the struct so
that it can be placed on an 8-byte boundary. The compiler generates
code to retrieve the elements of the array 8-bytes at a time and unaligned
access to 8-byte-wide data on this particular implementation is not
allowed.

The automatic char[20] variable A is not aligned on an 8-byte boundary, so
when it's accessed through the struct, unaligned access occurs and our
implementation spits the dummy.

So Joe - no go. Thou code be fraught.

<snip> may I have C&V for that?


There is no constraint violation if that's what you mean.


He meant "Chapter & Verse". :-D


The & did seem a little out of place...

Nov 15 '05 #21

P: n/a
Tim Rentsch wrote:
Joe Wright <jw*****@comcast.net> writes:

All of S is an array of char. What alignment requirements
might there be for an S? None. Structures don't have
alignment requirements, their members do. What are the
alignment requirements of a char array?

Structures can have alignment requirements that
are different from those of their members, and
here's a possible reason why they would.

On platforms where a 'char *' is a different
format and/or wider than an 'int *', an
implementation might choose to make all structs
be 'int' aligned, so that structure pointers
would be easier to deal with.

So a structure holding a character array would
still need 'int' alignment, even though the
contained character array would need only 'char'
alignment.

The alignment requirement also implies a sizing
requirement, since alignment_of(T) must evenly
divide 'sizeof(T)'. That's why a struct that
holds only a character array might be bigger
than the character array it holds.


You just made all that up didn't you?

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #22

P: n/a
Netocrat wrote:
On Sat, 06 Aug 2005 17:08:29 +0000, S.Tobias wrote:

Netocrat <ne******@membersat.dodo.com.au> wrote:
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:

Jack Klein wrote:
<snip>

>>/* Assign array via struct */
>>
>>#include <stdio.h>
>>#include <string.h>
>>#include <stdlib.h>
>>
>>#define LEN 20
>>
>>typedef struct {
>> char a[LEN];
>>} S;
>>
>>int main(void) {
>> S sa;
>> char A[LEN];
>>
>> S *ps = malloc(LEN);

It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
to use sizeof(S) than LEN.
>> char *pa = malloc(LEN);
>>
>> strcpy(sa.a, "Joe Wright Rocks");
>> puts(sa.a);
>>
>> *(S*)A = sa;


[snip]
>Here is where you invoke undefined behavior, since A isn't dynamically
>allocated. There is no guarantee that A meets the alignment
>requirements for an S. The compiler might generate code that assumes
>that A is, causing some sort of trap on some platforms, or possible
>misaligned data or overwriting the destination array.
<snipped two lines above restored>
Given that element a must be located at the start of struct S, and that it
is a char array of size LEN, it's hard to see how it could be aligned
differently to the char array A of size LEN. Are you referring to this
specific case or in general? If this case, could you explain how the
standard allows the alignments to be different?


Type `char' has no alignment (ie. alignment(char) == 1), of course,
but at issue is not `char', but rather `char[10]'. Long time ago

Actually Joe's code #define's LEN to 20, you're thinking of the OP.

(don't ask me for details now) I read that on DEC stations character
arrays in structs could have different alignments depending on their
size, so for example `char[15]' could have different alignment than
`char[31]'. All this was for purpose of memory access speed; ordinarily
`char[ANY]' doesn't have alignment (at least when ANY is a prime number,
for others I don't know), but when in a struct, a compiler
could assume that the array is positioned at a "fast" location and
generate more optimal code. (BTW, the discussion in which I read it
was about why struct-hack didn't work.)

Well you've confirmed that it's not merely hypothetical - padding
actually is added in some real-world implementations. So to expand on
Jack's explanation of specific code being generated, perhaps something
like this:

4 padding bytes are added after the array of 20 char in the struct so
that it can be placed on an 8-byte boundary. The compiler generates
code to retrieve the elements of the array 8-bytes at a time and unaligned
access to 8-byte-wide data on this particular implementation is not
allowed.

The automatic char[20] variable A is not aligned on an 8-byte boundary, so
when it's accessed through the struct, unaligned access occurs and our
implementation spits the dummy.

So Joe - no go. Thou code be fraught.

I think not. Consider..

struct {
char a[17];
} sa;

...and explain any case for sizeof sa not being 17. Annecdotes of long
forgotten DEC Stations don't count.
<snip>
may I have C&V for that?

There is no constraint violation if that's what you mean.


He meant "Chapter & Verse". :-D

The & did seem a little out of place...

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #23

P: n/a
On Sat, 06 Aug 2005 18:22:50 -0400, Joe Wright wrote:
Netocrat wrote:
>Jack Klein wrote:
>>Joe Wright wrote: <snip>>>>#define LEN 20
>>>
>>>typedef struct {
>>> char a[LEN];
>>>} S;
>>>
>>>int main(void) {
>>> S sa;
>>> char A[LEN];
>>>
>>> S *ps = malloc(LEN); <snip>>>> *(S*)A = sa;

[snip]

>>Here is where you invoke undefined behavior, since A isn't dynamically
>>allocated. There is no guarantee that A meets the alignment
>>requirements for an S. The compiler might generate code that assumes
>>that A is, causing some sort of trap on some platforms, or possible
>>misaligned data or overwriting the destination array.
<snip> So to expand on
Jack's explanation of specific code being generated, perhaps something
like this:

4 padding bytes are added after the array of 20 char in the struct so
that it can be placed on an 8-byte boundary. The compiler generates
code to retrieve the elements of the array 8-bytes at a time and unaligned
access to 8-byte-wide data on this particular implementation is not
allowed.

The automatic char[20] variable A is not aligned on an 8-byte boundary, so
when it's accessed through the struct, unaligned access occurs and our
implementation spits the dummy.

So Joe - no go. Thou code be fraught.

Correction: thy code be fraught. Thou codest flawed source.
I think not. Consider..

struct {
char a[17];
} sa;

..and explain any case for sizeof sa not being 17. Annecdotes of long
forgotten DEC Stations don't count.


Why not? Were they not valid C implementation hosts?

That's a contrived choice because being (2 pow 4) + 1 it's impossible to
minimise accesses. Using my example above, consider a 20-byte array
accessed in 8-byte chunks. When aligned on an 8-byte (or 4-byte)
boundary, it will take 3 accesses to read/write the entire array in
8-byte chunks. It will take 4 accesses to do the same when its alignment
is 1, 2 or 3 bytes off an 8-byte alignment. That's a supportable reason
for properly aligning the struct on an 8-byte boundary and hence requiring
4 padding bytes.

As for your 17 byte example, well, this implementation may pad out 7
bytes but more likely it would pad 3 and it would access 4 bytes at a time
on a 4-byte boundary.

Totally hypothetical but for all I know (I don't have a lot of varied
hardware experience) a machine like this does exist. Not the machine that
I work from though (Intel P4) because unaligned access whilst slower is
not an error.

Nov 15 '05 #24

P: n/a
>Tim Rentsch wrote:
On platforms where a 'char *' is a different
format and/or wider than an 'int *', an
implementation might choose to make all structs
be 'int' aligned, so that structure pointers
would be easier to deal with.

So a structure holding a character array would
still need 'int' alignment, even though the
contained character array would need only 'char'
alignment.

The alignment requirement also implies a sizing
requirement, since alignment_of(T) must evenly
divide 'sizeof(T)'. That's why a struct that
holds only a character array might be bigger
than the character array it holds.

In article <lJ********************@comcast.com>
Joe Wright <jw*****@comcast.net> wrote:You just made all that up didn't you?


He may well have made it up. But it was in fact the case on
the Data General MV/10000 (Eclipse), as I recall.

The Eclipse did actually have separate "word pointers" and "byte
pointers". Most pointers were word pointers; "char *" (and thus
"void *", had it existed) used byte pointers. To convert from byte
to word pointer, you shifted right one bit, discarding the byte-offset
and introducing a zero bit at the top (in the "indirect" bit that
appeared only in word pointers). To convert a word pointer to a
byte pointer, you shifted left one bit, discarding the top (indirect)
bit and introducing a zero bit at the bottom -- so that the resulting
byte pointer pointed to the first, even-numbered byte of the two
bytes that made up each word.

This machine exposed an awful lot of code-conformance problems,
even before the C standard existed. :-) We had one at the University
of Maryland in the mid-1980s, before the 1989 C standard came out.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 15 '05 #25

P: n/a
Joe Wright <jw*****@comcast.net> writes:
Tim Rentsch wrote:
Joe Wright <jw*****@comcast.net> writes:

All of S is an array of char. What alignment requirements
might there be for an S? None. Structures don't have
alignment requirements, their members do. What are the
alignment requirements of a char array?

Structures can have alignment requirements that
are different from those of their members, and
here's a possible reason why they would.

On platforms where a 'char *' is a different
format and/or wider than an 'int *', an
implementation might choose to make all structs
be 'int' aligned, so that structure pointers
would be easier to deal with.

So a structure holding a character array would
still need 'int' alignment, even though the
contained character array would need only 'char'
alignment.

The alignment requirement also implies a sizing
requirement, since alignment_of(T) must evenly
divide 'sizeof(T)'. That's why a struct that
holds only a character array might be bigger
than the character array it holds.


You just made all that up didn't you?


In fact, I didn't. I read about such platforms here
in comp.lang.c.

For example, consider a machine that addresses 64-bit
words natively. Pointers and ints are both 64 bits,
and use word addresses. A 64-bit word holds 8
eight-bit char's; a pointer to char uses a word
address, but puts the three bits that indicate which
char within the word in the high order bits of the
64-bit pointer. I'm doing this from memory, so I may
have some of the details wrong; however, other people
have written about C implementations on actual machines
that are very much like this.

It would be very natural on such a machine to have
all struct's be multiples of 8 in size, and aligned
on word boundaries.
Nov 15 '05 #26

P: n/a
On Sun, 07 Aug 2005 00:24:58 +1000, Netocrat
<ne******@membersat.dodo.com.au> wrote:
On Sat, 06 Aug 2005 08:45:05 -0400, Joe Wright wrote:
Netocrat wrote:
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:
Jack Klein wrote:
<snip>

>>/* Assign array via struct */
>>
>>#include <stdio.h>
>>#include <string.h>
>>#include <stdlib.h>
>>
>>#define LEN 20
>>
>>typedef struct {
>> char a[LEN];
>>} S;
>>
>>int main(void) {
>> S sa;
>> char A[LEN];
>>
>> S *ps = malloc(LEN);
It's possible, but unlikely, that sizeof(S) > LEN due to padding. Better
to use sizeof(S) than LEN.

What padding could there be? S is essentially a char array.


Yeah, that's why I called it a pedantic point later in the post. Probably
the DS9000 is the only implementation to include padding. Anyhow you lose
nothing by using sizeof(S) instead of LEN and you are assured of
compliance.


No, it isn't a pedantic point, there are many systems where a struct is
rounded up in length to the "worst case~ alignment size. In the case
given, it probably won't happen all that often because LEN is 20 which
is a multiple of 4 (although certain 64 bit machines may need alignment
to 8 byte boundaries). If LEN were an odd number a lot of systems would
round the size up to at least the nearest even number.
>> char *pa = malloc(LEN);
>>
>> strcpy(sa.a, "Joe Wright Rocks");
>> puts(sa.a...);
>>
>> *(S*)A = sa;
Here you are potentially copying and assigning more than the allocated
(to src and dest) LEN bytes. A compiler might do this for performance
reasons. It's probably unlikely and a little pedantic but the point is
that what you're doing isn't guaranteed safe by the standard.

You're assuming sizeof sa might be greater than LEN. Why?


As above - padding. I wrote that it might be added for performance
reasons. I don't know if such reasons legitimately exist on a real-world
implementation (I can contrive a far-fetched hypothetical implementation
where they do), but you never know what code an optimising compiler is
going to generate.


Or a non-optimising one. A fully optimising compiler might notice that
the only thing in the structure is a char array, and hence generate a
structure of length LEN, where a non-optimising one would "play it safe"
by making sure that it is rounded up to a safe alignment.

If there are non-char elements in the structure, of course, the size
will always be rounded up to the worst alignment needed by any field in
the structure. This is because it could be used as an array, and the
array accesses must be correctly aligned.

The only portable way to do malloc is to use the sizeof the actual thing
being allocated:

char *pa = malloc(sizeof(S));

or preferably

S *ps = malloc(sizeof(*ps));

Chris C
Nov 15 '05 #27

P: n/a
On Sat, 06 Aug 2005 08:02:38 -0400, Joe Wright wrote:
Jack Klein wrote:
On Fri, 05 Aug 2005 16:24:25 -0400, Joe Wright <jw*****@comcast.net>
wrote in comp.lang.c:

Lawrence Kirby wrote:
....
*(S*)A = sa;

Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes
that A is, causing some sort of trap on some platforms, or possible
misaligned data or overwriting the destination array.

All of S is an array of char. What alignment requirements might there be
for an S? None. Structures don't have alignment requirements, their
members do. What are the alignment requirements of a char array?


Any object type can have alignment requirements. A structure's alignment
requirements must meet the requirements of all of its members, but there's
nothing to stop it being stricter. The reason for doing this is speed,
word aligned access can be faster even for smaller objects. Consider for
example optimised strcpy() memcpy() etc. code that operates a word at a
time.

I strongly dislike people who write code like this. Especially if I
have to clean up after the 'clever' programmer. It would never pass a
code inspection at any shop with decent standards. Shops that don't
do code inspections don't have decent standards by definition.

You 'strongly dislike people' who try to get 'clever' with C in a
newsgroup posting? Boy, are you tough.


When the "clever" method is obscure and possibly wrong (or not easy to
prove correct) and there is "dumb" simple, clear and correct method
available I'd have to agree.
I thought you'd get me for not checking the malloc() returns and not
free()ing ps and pa before exit. You never know your luck.


There's that too. :-)

Lawrence
Nov 15 '05 #28

P: n/a
Chris Croughton <ch***@keristor.net> writes:
On Sun, 07 Aug 2005 00:24:58 +1000, Netocrat
<ne******@membersat.dodo.com.au> wrote:

[snip]
Yeah, that's why I called it a pedantic point later in the post. Probably
the DS9000 is the only implementation to include padding. Anyhow you lose
nothing by using sizeof(S) instead of LEN and you are assured of
compliance.


No, it isn't a pedantic point, there are many systems where a struct is
rounded up in length to the "worst case~ alignment size. In the case
given, it probably won't happen all that often because LEN is 20 which
is a multiple of 4 (although certain 64 bit machines may need alignment
to 8 byte boundaries). If LEN were an odd number a lot of systems would
round the size up to at least the nearest even number.


For example, given:

struct foo {
char s[3];
};

it would make sense on many platforms to pad struct foo to 4 bytes and
require 4-byte alignment. That way, assigning a struct foo or passing
it as an argument could be done with a single 4-byte instruction, just
as for a 32-bit (assuming CHAR_BIT==8) integer.

On the other hand, an implementer might decide that copying structures
is rare enough that the extra padding isn't worthwhile. <OT>gcc
doesn't add extra padding, at least by default, at least on the one
platform where I tried this.</OT>

[snip]
As above - padding. I wrote that it might be added for performance
reasons. I don't know if such reasons legitimately exist on a real-world
implementation (I can contrive a far-fetched hypothetical implementation
where they do), but you never know what code an optimising compiler is
going to generate.


Or a non-optimising one. A fully optimising compiler might notice that
the only thing in the structure is a char array, and hence generate a
structure of length LEN, where a non-optimising one would "play it safe"
by making sure that it is rounded up to a safe alignment.


But note that the non-optimizing and fully optimizing compilers in
practice probably can't be the same compiler in different modes.
Given the way most compilers are invoked, you usually want to have the
same data layout in all modes, since a program can be built from
translation units that were compiled in different modes. (Or the
linker can forbid linking units compiled in different modes, but that
makes things more complicated.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #29

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Joe Wright <jw*****@comcast.net> writes: [snip]
You just made all that up didn't you?


In fact, I didn't. I read about such platforms here
in comp.lang.c.

For example, consider a machine that addresses 64-bit
words natively. Pointers and ints are both 64 bits,
and use word addresses. A 64-bit word holds 8
eight-bit char's; a pointer to char uses a word
address, but puts the three bits that indicate which
char within the word in the high order bits of the
64-bit pointer. I'm doing this from memory, so I may
have some of the details wrong; however, other people
have written about C implementations on actual machines
that are very much like this.


Yes, Cray vector machines (at least the ones I've used) are like that.
It would be very natural on such a machine to have
all struct's be multiples of 8 in size, and aligned
on word boundaries.


In fact, I just tried the following program on a Cray Y-MP:

#include <stdio.h>
int main(void)
{
struct foo {
char s[3];
};
printf("sizeof(struct foo) = %d\n", (int)sizeof(struct foo));
return 0;
}

The output was:

sizeof(struct foo) = 8

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 15 '05 #30

P: n/a
Lawrence Kirby wrote:
On Sat, 06 Aug 2005 08:02:38 -0400, Joe Wright wrote:

Jack Klein wrote:
On Fri, 05 Aug 2005 16:24:25 -0400, Joe Wright <jw*****@comcast.net>
wrote in comp.lang.c:

Lawrence Kirby wrote:

...

*(S*)A = sa;
Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes
that A is, causing some sort of trap on some platforms, or possible
misaligned data or overwriting the destination array.


All of S is an array of char. What alignment requirements might there be
for an S? None. Structures don't have alignment requirements, their
members do. What are the alignment requirements of a char array?

Any object type can have alignment requirements. A structure's alignment
requirements must meet the requirements of all of its members, but there's
nothing to stop it being stricter. The reason for doing this is speed,
word aligned access can be faster even for smaller objects. Consider for
example optimised strcpy() memcpy() etc. code that operates a word at a
time.
I strongly dislike people who write code like this. Especially if I
have to clean up after the 'clever' programmer. It would never pass a
code inspection at any shop with decent standards. Shops that don't
do code inspections don't have decent standards by definition.


You 'strongly dislike people' who try to get 'clever' with C in a
newsgroup posting? Boy, are you tough.

When the "clever" method is obscure and possibly wrong (or not easy to
prove correct) and there is "dumb" simple, clear and correct method
available I'd have to agree.

I thought you'd get me for not checking the malloc() returns and not
free()ing ps and pa before exit. You never know your luck.

There's that too. :-)

Lawrence


Ok, I give up.

Too clever I suppose. Except for this thread, I don't think I've ever
done that: disguise an array as a struct so that it can be assigned to
or used as a value to be assigned to a struct.

Kieth, Stan, Netocrat and Tim notwithstanding, when Chris Torek and
Lawrence Kirby tell me I'm all wet, I'm wet.

It's not just C, I love this group too.

--
Joe Wright
"Everything should be made as simple as possible, but not simpler."
--- Albert Einstein ---
Nov 15 '05 #31

P: n/a
Regarding my post:

Thanks to all who replied to me, I didn't expected such a number of (highly
interresting) answers.

I mostly note that padding and alignment could cause the implementation to
be not portable, so I'll do it differently.

Why I wanted to do this this way was because I had to implement some kind of
side effect to assignments, and, like C, assignments are nothing more than
binary operators that return a value, so a=b=c+d is effectively
a=(b=(c+d)). Seeing the gold mine of knowledge here, I know you all know
that. Now I know, that's why functions like memcpy returns the destination
pointer, so that this can be done too, but I had to also call another
function concurrently, and I looked for an easy way to achieve what I had
in mind.

My final solution, and I feel somewhat ashamed for having thought of this so
late, is simply to wrap up the memcpy and the side-effect functions in an
inline function, so code-generation will still be easilly done and *much*
more cleaner. Clean code, no matter if it's human or computer generated, is
essential for me too. "Better safe than sorry".

Thanks again,
--
Eric Laberge
Nov 15 '05 #32

P: n/a
On Mon, 08 Aug 2005 19:56:13 GMT, Keith Thompson
<ks***@mib.org> wrote:
Chris Croughton <ch***@keristor.net> writes:
On Sun, 07 Aug 2005 00:24:58 +1000, Netocrat
<ne******@membersat.dodo.com.au> wrote: [snip]
Yeah, that's why I called it a pedantic point later in the post. Probably
the DS9000 is the only implementation to include padding. Anyhow you lose
nothing by using sizeof(S) instead of LEN and you are assured of
compliance.


No, it isn't a pedantic point, there are many systems where a struct is
rounded up in length to the "worst case~ alignment size. In the case
given, it probably won't happen all that often because LEN is 20 which
is a multiple of 4 (although certain 64 bit machines may need alignment
to 8 byte boundaries). If LEN were an odd number a lot of systems would
round the size up to at least the nearest even number.


For example, given:

struct foo {
char s[3];
};

it would make sense on many platforms to pad struct foo to 4 bytes and
require 4-byte alignment. That way, assigning a struct foo or passing
it as an argument could be done with a single 4-byte instruction, just
as for a 32-bit (assuming CHAR_BIT==8) integer.


Yes, efficiency of generated code is one of the reasons for doing it.
On the other hand, even a compiler which generates memcpy() (or its
assembler equivalent) for all copies might still round it up because it
rounds up all structures "just in case" (the standard doesn't say that
it can't). And of course on a word based machine it may only be able to
allocate chunks in multiple bytes anyway.
On the other hand, an implementer might decide that copying structures
is rare enough that the extra padding isn't worthwhile. <OT>gcc
doesn't add extra padding, at least by default, at least on the one
platform where I tried this.</OT>
<OT>
This may be a feature of gcc, it does it both on x86 (Debian Linux) and
on a MicroVAX 3100/M40 running OpenBSD (unfortunately my uVAX 3100/90
running OpenVMS with the Digital C compliler isn't working at the
moment, and I don't have any Sun Sparcs or Digital Alpha machines online
at present). Ye gods, the uVAX is slow (5 minutes to test 32MB RAM
gives an idea)...
</OT>
[snip]
Or a non-optimising one. A fully optimising compiler might notice that
the only thing in the structure is a char array, and hence generate a
structure of length LEN, where a non-optimising one would "play it safe"
by making sure that it is rounded up to a safe alignment.


But note that the non-optimizing and fully optimizing compilers in
practice probably can't be the same compiler in different modes.
Given the way most compilers are invoked, you usually want to have the
same data layout in all modes, since a program can be built from
translation units that were compiled in different modes. (Or the
linker can forbid linking units compiled in different modes, but that
makes things more complicated.)


Yes, good point, although I've known compilers which generated
incompatible code when optimising for space vs. speed (sometimes putting
parameters in registers in one mode and not the other, for instance).
I've known gcc to have problems with optimised code interfacing to
non-optimised code, although that may have been a bug (but not forbidden
by the standard)...

Chris C
Nov 15 '05 #33

P: n/a
Eric Laberge wrote:

Regarding my post:

Thanks to all who replied to me,
I didn't expected such a number of (highly
interresting) answers.

I mostly note that padding and alignment could
cause the implementation to
be not portable, so I'll do it differently.


I don't get it. The code I posted here:

http://groups-beta.google.com/group/...17f3f78?hl=en&

is portable code.

--
pete
Nov 15 '05 #34

P: n/a
On Mon, 08 Aug 2005 16:18:11 -0400, Joe Wright
<jw*****@comcast.net> wrote:
Kieth, Stan, Netocrat and Tim notwithstanding, when Chris Torek and
Lawrence Kirby tell me I'm all wet, I'm wet.
When Chris Torek writes something, I read it, because not only is he
almost always[0] right but he also explains it so that I know /why/ he
is right and without being patronising or putting my back up. A lot of
people here (and I include myself) aren't that good at saying "You're
wrong" without offending people...

[0] Actually, always as far as I remember except for the Fortran program
where he got the label on the wrong line <g>...
It's not just C, I love this group too.


Well, I'm still here. Although I have killfiled a lot of the obvious
trolls (a couple of generic rules on gmail and yahoo addresses, with
certain exceptions[1], does wonders for the signal to noise ratio)...

[1] Since I use a scorefile rather than a killfile, I score at -999
which means that (a) if they respond to my posts they get 'unkilled' for
that response and (b) they are still visible so I can check if anyone
has been caught who shouldn't have been caught and can put them in the
exceptions list.

Chris C
Nov 15 '05 #35

P: n/a
On Mon, 08 Aug 2005 22:44:51 +0000, pete wrote:
Eric Laberge wrote:

Regarding my post:

Thanks to all who replied to me,
I didn't expected such a number of (highly
interresting) answers.

I mostly note that padding and alignment could
cause the implementation to
be not portable, so I'll do it differently.


I don't get it. The code I posted here:

http://groups-beta.google.com/group/...17f3f78?hl=en&

is portable code.


If you want to use a structure containing an array instead of an array in
your code that's fine. There may be problems if:

1. there is code that already creates arrays that are not structure
wrapped, and more seriously:

2. the size of the array is not known at compile time.

Lawrence

Nov 15 '05 #36

P: n/a
On Sat, 06 Aug 2005 17:19:44 +1000, Netocrat
<ne******@membersat.dodo.com.au> wrote:
On Fri, 05 Aug 2005 21:52:07 -0700, Krishanu Debnath wrote:

Jack Klein wrote: <snip ... auto char A[N] accessed as struct containing char[N]>
Here is where you invoke undefined behavior, since A isn't dynamically
allocated. There is no guarantee that A meets the alignment
requirements for an S. The compiler might generate code that assumes


Given that element a must be located at the start of struct S, and that it
is a char array of size LEN, it's hard to see how it could be aligned
differently to the char array A of size LEN. Are you referring to this
specific case or in general? If this case, could you explain how the
standard allows the alignments to be different?

Except that certain pairs like qualified and unqualified pointers to
the same type must be the same, the standard allows the alignment of
anything except char to be anything the implementation wants, though
it nonnormatively expects transitivity, footnote 57 to 6.3.2.3p7.

"Classic" Tandem^WCompaq^WHP NonStop, still supported in emulation, is
(was) 16-bit-word (=2 x 8-bit byte) oriented, and requires basic types
above char (>= short) to be word aligned, and _all_ struct (and union)
even if they contain only char(s). Hence a char [N] might sometimes
not be word-aligned while a struct { char x [N] } must. Although, on
that implementation a "top-level" array variable is always allocated
word-aligned, so the case _given here_ was OK.

- David.Thompson1 at worldnet.att.net
Nov 15 '05 #37

This discussion thread is closed

Replies have been disabled for this discussion.