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;
} 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
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
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. This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
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...
|
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,
|
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...
|
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;
|
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...
|
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
|
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;
|
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...
|
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...
|
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...
|
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...
|
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,...
|
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...
|
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...
|
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...
|
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,...
|
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...
|
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...
| |