473,420 Members | 1,622 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,420 software developers and data experts.

alignment/zero length arrays

I have a program that does most of its work traversing
a bunch of lists. The lists contain a void *, and I spent
some time today replacing the void *'s with a copy
of the data at the end of the structure as a zero length
array. The performance improvement that resulted by
avoiding the need to dereference the ptr was substantial,
but it has left me with an uncertain feeling. In particular,
changing an assignment caused the output to change,
and I'm not happy about it. The change that I think
should not have any affect is:

struct foo *f;
f = (struct foo *)&list_element->zdata;

becomes

struct foo f;
f = *(struct foo *)&list_element->zdata;

This is better described with the full program below.
My question is: 1) Are the final 3 assignments in this program
reliable?

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

struct foo {
int x,y,z;
};
struct list_el {
void *data;
/* other stuff that throws off alignment */
/* gnu extension...*/
char zdata[] __attribute__((aligned(8)));
};

extern void * xmalloc(size_t s);

int
main(void)
{
struct list_el *L;
struct foo orig = {0,1,2};
struct foo *copy_ptr;
struct foo copy;

L = xmalloc(sizeof *L + sizeof orig);
L->data = &orig;
memcpy(&L->zdata, &orig, sizeof orig);

copy_ptr = (struct foo *)L->data;

copy_ptr = (struct foo *)&L->zdata;

copy = *(struct foo*)&L->zdata;

return EXIT_SUCCESS;
}

Aug 25 '06 #1
3 2482
On 25 Aug 2006 11:28:07 -0700, "Bill Pursell" <bi**********@gmail.com>
wrote:
>I have a program that does most of its work traversing
a bunch of lists. The lists contain a void *, and I spent
some time today replacing the void *'s with a copy
of the data at the end of the structure as a zero length
array. The performance improvement that resulted by
avoiding the need to dereference the ptr was substantial,
but it has left me with an uncertain feeling. In particular,
changing an assignment caused the output to change,
and I'm not happy about it. The change that I think
should not have any affect is:
We would have to see your real code to discuss this. For example, do
you reuse the struct?
>
struct foo *f;
f = (struct foo *)&list_element->zdata;
This sets pointer f to point to the data in your element.
>
becomes

struct foo f;
f = *(struct foo *)&list_element->zdata;
This copies the data from your element to the structure f.
>
This is better described with the full program below.
My question is: 1) Are the final 3 assignments in this program
reliable?

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

struct foo {
int x,y,z;
};
struct list_el {
void *data;
/* other stuff that throws off alignment */
/* gnu extension...*/
char zdata[] __attribute__((aligned(8)));
The first part of this is a syntax error. (You could achieve the
intended result with [1].) The second part is non-standard. It also
begs the question how do you know 8 is the proper alignment.
>};

extern void * xmalloc(size_t s);

int
main(void)
{
struct list_el *L;
struct foo orig = {0,1,2};
struct foo *copy_ptr;
struct foo copy;

L = xmalloc(sizeof *L + sizeof orig);
You don't provide xmalloc but I will assume it does the obvious.
L->data = &orig;
memcpy(&L->zdata, &orig, sizeof orig);

copy_ptr = (struct foo *)L->data;
The cast is superfluous. data is a void* which can be implicitly
converted to any other object pointer type.

In answer to your question, data contains the address of a struct foo.
copy_ptr is a pointer to struct foo. It is reliable to assign such an
address to such a pointer. The conversion to void* (three statements
prior) and from void* (here) are well defined.
>
copy_ptr = (struct foo *)&L->zdata;
This is "reliable" only if zdata is properly aligned to a struct foo.
>
copy = *(struct foo*)&L->zdata;
This also is "reliable" only if zdata is properly aligned.
>
return EXIT_SUCCESS;
}

Remove del for email
Aug 25 '06 #2
Barry Schwarz wrote:
On 25 Aug 2006 11:28:07 -0700, "Bill Pursell" <bi**********@gmail.com>
wrote:
I have a program that does most of its work traversing
a bunch of lists. The lists contain a void *, and I spent
some time today replacing the void *'s with a copy
of the data at the end of the structure as a zero length
array. The performance improvement that resulted by
avoiding the need to dereference the ptr was substantial,
but it has left me with an uncertain feeling. In particular,
changing an assignment caused the output to change,
and I'm not happy about it. The change that I think
should not have any affect is:

We would have to see your real code to discuss this. For example, do
you reuse the struct?

struct foo *f;
f = (struct foo *)&list_element->zdata;

This sets pointer f to point to the data in your element.

becomes

struct foo f;
f = *(struct foo *)&list_element->zdata;

This copies the data from your element to the structure f.

This is better described with the full program below.
My question is: 1) Are the final 3 assignments in this program
reliable?

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

struct foo {
int x,y,z;
};
struct list_el {
void *data;
/* other stuff that throws off alignment */
/* gnu extension...*/
char zdata[] __attribute__((aligned(8)));

The first part of this is a syntax error. (You could achieve the
intended result with [1].) The second part is non-standard. It also
begs the question how do you know 8 is the proper alignment.
What's the syntax error? Is [] a gnu extension, and I should instead
use [0]? gcc happily compiled with -Wall -pedantic -std=c99
Does zdata need to
have size 1? I'd rather avoid giving it any space, since I'm using
the data structure somewhat flexibly. ie, the structure is
defined with:

#define declare_list_of_(x) struct list_el_##x {\
x data;\
/* more stuff */\
char zdata [];\
}

typedef void *vp
declare_list_of(int);
declare_list_of(vp);
etc...

The list of int won't use the zdata field, so there's no
point allocating space for it.

(Note, the "more stuff" includes function pointers
for manipulating the lists, so they contain more references
to x in the argument lists. I'm not really sure I like this
set up, as I can see it quickly becoming unweildy.)

<snip>
>
L->data = &orig;
memcpy(&L->zdata, &orig, sizeof orig);

copy_ptr = (struct foo *)L->data;

The cast is superfluous. data is a void* which can be implicitly
converted to any other object pointer type.
Yeah, I was just trying to make all the assignments symmetric
to try to clarify what I'm having a problem with.
>
In answer to your question, data contains the address of a struct foo.
copy_ptr is a pointer to struct foo. It is reliable to assign such an
address to such a pointer. The conversion to void* (three statements
prior) and from void* (here) are well defined.

copy_ptr = (struct foo *)&L->zdata;

This is "reliable" only if zdata is properly aligned to a struct foo.
So the alignment issue is really the heart of the quesion. You
asked above how I know that 8 is the correct alignment, and
the answer is that I don't. Currently, I'm providing an API
that allows a function to do:
array_of_int *a;
array_of_float *b;
array_of_vp *c;
struct foo f = {1,2,3};

a = abc_create_array( /* some args */, INT).i;
b = abc_create_array( /* some args */, FLOAT).f;
c = abc_create_array( /* some args */, VOID_PTR).vp;
a->insert(a, 5);
b->insert(b,5.0);
c->insert(c, &f);

Where abc_create_array returns a
union {
array_of_int *i;
array_of_float *f;
array_of_vp *vp;
};
I'd like to modify the API to do:
d = abc_create_array( /* some args */, VAR, sizeof f).vp;
d->insert(d, &f)

Where the assignment to d copies the data into the
array rather than merely adding the pointer. So I don't
know the alignment, but in the particular instance I'm
doing, the data I'm inserting is 4 floats. I'll try
setting the alignment to 16, but I don't think it should
matter, since the current setup has sizeof( struct list_el) == 32.
(ie, the zero length array is already aligned on a 32 byte
boundary)

Can the structure be aligned portably? I only know how
to do it except by relying on gcc's aligned attribute.

--
Bill Pursell

Aug 26 '06 #3
Bill Pursell schrieb:
Barry Schwarz wrote:
>>On 25 Aug 2006 11:28:07 -0700, "Bill Pursell" <bi**********@gmail.com>
wrote:
>>>I have a program that does most of its work traversing
a bunch of lists. The lists contain a void *, and I spent
some time today replacing the void *'s with a copy
of the data at the end of the structure as a zero length
array. The performance improvement that resulted by
avoiding the need to dereference the ptr was substantial,
but it has left me with an uncertain feeling. In particular,
changing an assignment caused the output to change,
and I'm not happy about it. The change that I think
should not have any affect is:

We would have to see your real code to discuss this. For example, do
you reuse the struct?
>>>struct foo *f;
f = (struct foo *)&list_element->zdata;

This sets pointer f to point to the data in your element.
>>>becomes

struct foo f;
f = *(struct foo *)&list_element->zdata;

This copies the data from your element to the structure f.
>>>This is better described with the full program below.
My question is: 1) Are the final 3 assignments in this program
reliable?

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

struct foo {
int x,y,z;
};

struct list_el {
void *data;
/* other stuff that throws off alignment */
/* gnu extension...*/
char zdata[] __attribute__((aligned(8)));

The first part of this is a syntax error. (You could achieve the
intended result with [1].) The second part is non-standard. It also
begs the question how do you know 8 is the proper alignment.

What's the syntax error? Is [] a gnu extension, and I should instead
use [0]? gcc happily compiled with -Wall -pedantic -std=c99
No, this is perfectly standard C99, c.f. 6.7.2.1.
Note that -- if we assume for one moment that the __attribute__....
is not present -- gcc got the following wrong in the past:
sizeof(struct list_el) == offsetof(struct list_el, zdata)
&&
sizeof(struct list_el) == offsetof(struct list_el_2, zdata)
where
struct list_el_2 {
void *data;
/* other stuff that throws off alignment */
/* gnu extension...*/
char zdata[1];
};
I have no current gcc on my machine but in past C99 status
documents, there was a link to some thread where the gcc
people debated the wisdom of these semantics and seemed ready
to decide to ignore the standard.
Does zdata need to
have size 1? I'd rather avoid giving it any space, since I'm using
the data structure somewhat flexibly. ie, the structure is
defined with:

#define declare_list_of_(x) struct list_el_##x {\
x data;\
/* more stuff */\
char zdata [];\
}
Note: If you want to use zdata for something which has nothing
to do with strings, then make that "unsigned char zdata[];".
char is for characters, unsigned char for everything where you
want one byte in its full representation.
typedef void *vp
declare_list_of(int);
declare_list_of(vp);
etc...

The list of int won't use the zdata field, so there's no
point allocating space for it.

(Note, the "more stuff" includes function pointers
for manipulating the lists, so they contain more references
to x in the argument lists. I'm not really sure I like this
set up, as I can see it quickly becoming unweildy.)
I think this is a question of its own.
>
<snip>
>> L->data = &orig;
memcpy(&L->zdata, &orig, sizeof orig);

copy_ptr = (struct foo *)L->data;

The cast is superfluous. data is a void* which can be implicitly
converted to any other object pointer type.

Yeah, I was just trying to make all the assignments symmetric
to try to clarify what I'm having a problem with.
I did not understand what you want in your OP and still do not
know where your exact problem lies. All the unnecessary casts
contributed to the impression "maybe he does not know what he
wants".
>>In answer to your question, data contains the address of a struct foo.
copy_ptr is a pointer to struct foo. It is reliable to assign such an
address to such a pointer. The conversion to void* (three statements
prior) and from void* (here) are well defined.
>> copy_ptr = (struct foo *)&L->zdata;

This is "reliable" only if zdata is properly aligned to a struct foo.

So the alignment issue is really the heart of the quesion. You
asked above how I know that 8 is the correct alignment, and
the answer is that I don't. Currently, I'm providing an API
that allows a function to do:
array_of_int *a;
array_of_float *b;
array_of_vp *c;
struct foo f = {1,2,3};

a = abc_create_array( /* some args */, INT).i;
b = abc_create_array( /* some args */, FLOAT).f;
c = abc_create_array( /* some args */, VOID_PTR).vp;
a->insert(a, 5);
b->insert(b,5.0);
c->insert(c, &f);

Where abc_create_array returns a
union {
array_of_int *i;
array_of_float *f;
array_of_vp *vp;
};
I'd like to modify the API to do:
d = abc_create_array( /* some args */, VAR, sizeof f).vp;
d->insert(d, &f)

Where the assignment to d copies the data into the
array rather than merely adding the pointer.
Hmmm, I am too tired and caffeine-deprived at the moment for
sound judgement but I don't like it at first glance.
So I don't
know the alignment, but in the particular instance I'm
doing, the data I'm inserting is 4 floats. I'll try
setting the alignment to 16, but I don't think it should
matter, since the current setup has sizeof( struct list_el) == 32.
(ie, the zero length array is already aligned on a 32 byte
boundary)

Can the structure be aligned portably? I only know how
to do it except by relying on gcc's aligned attribute.
No. Otherwise, you could provide a portable malloc().
It is not possible to do this for each and every
possible type. What you _can_ do is
union zdata_ {
unsigned char zdata[1]; /* zdata itself */
/* alignment providers: */
float f[1]; double d[1]; long double ld[1];
long l[1]; void *pv[1]; void **ppv[1]; int *pi[1];
/* missing: pointers to struct, long long etc */
....
};
struct list_el {
x data;
/*stuff*/
union zdata_ zdata[];
};
This is, of course, unspeakably ugly and not guaranteed to
work on each and every implementation. Usually, long, (long long,
int_max_t,) double, long double, void * and maybe int (*)()
are enough.
Cheers
Michael
--
E-Mail: Mine is an /at/ gmx /dot/ de address.
Aug 26 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Shashi | last post by:
Can somebody explain how the byte alignment for structures work, taking the following example and considering: byte of 1 Byte word of 2 Bytes dword of 4 Bytes typedef struct { byte a; word...
8
by: Vu Pham | last post by:
If I have sometype ar; then does the following command clear the whole array to zero ? memset( ar, 0, A*B*sizeof(sometype) ); Thanks,
31
by: RS | last post by:
Hi, Looking to see if the following construct is valid: typedef struct { int foo; char bar; } foobar; Basically, the idea is to have the structure above point to a message buffer that has...
8
by: pranav.choudhary | last post by:
Is it legal to keep the size of an array 0. gcc 3.4.2 did not give any error for the declaration int a; If the declaration is legal, then what will be the implications of saying a = 10;
22
by: spam.noam | last post by:
Hello, I discovered that I needed a small change to the Python grammar. I would like to hear what you think about it. In two lines: Currently, the expression "x" is a syntax error. I suggest...
5
by: $hiv..... | last post by:
hi, How to use Zero lengh Arrays.. I searched but could not get much information regarding this where Do i get links abt this
19
by: nileshsimaria | last post by:
Hi, I have seen some code were we have array with zero elements (mostly within structure) like, typedef struct foo { int data }foo;
33
by: Zytan | last post by:
I want to make a zero element array. I know that Nothing is not the same as a zero element array, since I can't get the length of, or iterate through, an array = Nothing. I could make a zero...
18
by: H.K. Kingston-Smith | last post by:
I understand that a line like char *a = malloc(64) ; when succeeding will initialize a to a pointer that is aligned at worst on the natural boundary of the underlying architecture, possibly on...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.