Need Help Declaring a Pointer to an Array of Structures

G

gcary

I am having trouble figuring out how to declare a pointer to an array
of structures and initializing the pointer with a value. I've looked
at older posts in this group, and tried a solution that looked
sensible, but it didn't work right. Here is a simple example of what
I'm trying to accomplish:

// I have a hardware peripheral that I'm trying to access
// that has two ports. Each port has 10 sequential
// registers. Create a structure definition that
// defines a single port.

typedef struct {
long long1;
long long2;
long long3;
long long4;
long long5;
long long6;
long long7;
long long8;
long long9;
long long10;
} volatile my_struct;

// Create a pointer to an array of two structures
my_struct (*my_struct_ptr)[2];

#define PERIPHERAL_BASEADDR 0xA0000000

int main(int argc, char **argv)
{
// This is the syntax I came up with to initialize
// the pointer. Keep in mind that this line of code
// isn't even needed in this example to illustrate the
// behavior of the compiler with respect to addressing.
my_struct_ptr = (my_struct (*)[])PERIPHERAL_BASEADDR;

printf("&my_struct_ptr[0] = %08X\n",
&my_struct_ptr[0]);

printf("&my_struct_ptr[1] = %08X\n",
&my_struct_ptr[1]);

printf("sizeof(my_struct) = %x\n",
sizeof(my_struct));

printf("sizeof(my_struct_ptr[0]) = %x\n",
sizeof(my_struct_ptr[0]));

printf("sizeof(my_struct_ptr[1]) = %x\n",
sizeof(my_struct_ptr[1]));

printf("&(my_struct_ptr[0]->long1) = %08X\n",
&(my_struct_ptr[0]->long1));

printf("&(my_struct_ptr[0]->long10) = %08X\n",
&(my_struct_ptr[0]->long10));

printf("&(my_struct_ptr[1]->long1) = %08X\n",
&(my_struct_ptr[1]->long1));

printf("&(my_struct_ptr[1]->long10) = %08X\n",
&(my_struct_ptr[1]->long10));
}

Here is the output of the program:

&my_struct_ptr[0] = A0000000
&my_struct_ptr[1] = A0000050
sizeof(my_struct) = 28
sizeof(my_struct_ptr[0]) = 50
sizeof(my_struct_ptr[1]) = 50
&(my_struct_ptr[0]->long1) = A0000000
&(my_struct_ptr[0]->long10) = A0000024
&(my_struct_ptr[1]->long1) = A0000050
&(my_struct_ptr[1]->long10) = A0000074

It correctly calculates the size of the typedef'd structure, but it
reports the size of each element of the array as twice as big as it
should be. If there are three elements in the array, then the size of
each element is 3 times as big. In this example, long1 of the second
element should be at address A0000028.

I am using the GCC compiler, but I don't think it is a bug in the
compiler. I tried it in Visual C++ and got the same results.

I tried to use a pointer to a single structure and use it like an
array. That only half works because the compiler doesn't see it as an
array of structures and therefore you can't access the elements of the
structure and index as well.

Any help would be appreciated.

Thanks,

Greg
 
C

Chris Torek

typedef struct { ... } volatile my_struct;

In general, I advise against making nameless structure types and
then giving them aliases. I suggest even more caution when mixing
// Create a pointer to an array of two structures
my_struct (*my_struct_ptr)[2];

[rest of code snipped]

You declare a "pointer to an array" here, just as your comment
implies; but you do not *want* a "pointer to an array", you want
a "pointer to an element". This is because a "pointer to T", for
some type T, often -- perhaps even "usually", and certainly in
your case -- points to the first of many elements of type "T" that
are in an array. A "pointer to array N of T" points to the first
array in an array of many arrays. In this case, you are making
the pointer point to the first "array 2 of T", so that p is
the i'th "array 2 of T". See <http://web.torek.net/torek/c/pa.html>.
 
G

gcary

Chris said:
In general, I advise against making nameless structure types and
then giving them aliases. I suggest even more caution when mixing
"volatile" in. See <http://web.torek.net/torek/c/types2.html>.
(Neither of these is the problem though.)

Chris, thanks for your help. Thanks for your advice about nameless
structure types. That makes some sense. I'll re-read your website
tomorrow when I'm more awake. About the volatile modifier, would you
recommend placing it on each of the elements of the structure rather
than the structure itself?
// Create a pointer to an array of two structures
my_struct (*my_struct_ptr)[2];

[rest of code snipped]

You declare a "pointer to an array" here, just as your comment
implies; but you do not *want* a "pointer to an array", you want
a "pointer to an element". This is because a "pointer to T", for
some type T, often -- perhaps even "usually", and certainly in
your case -- points to the first of many elements of type "T" that
are in an array. A "pointer to array N of T" points to the first
array in an array of many arrays. In this case, you are making
the pointer point to the first "array 2 of T", so that p is
the i'th "array 2 of T". See <http://web.torek.net/torek/c/pa.html>.


I understand what you're saying. I'll give it a shot tomorrow when I'm
back at work. I think you're saying that what I need to do is the
following:

my_struct (*mystruct_ptr)[1];

Then just treat the pointer as any other pointer. Like I said before,
I'll re-read your web pages tomorrow and hopefully get even more out of
it.

Thanks again for your help,

Greg
 
B

Barry Schwarz

I am having trouble figuring out how to declare a pointer to an array
of structures and initializing the pointer with a value. I've looked

Clarify your terminology. The phrase pointer to an array is
frequently misused to mean pointer to the first element of the array.
For a type T, this would be coded as T *ptr. To be technically
correct, a pointer to an array of type T would be coded as T (*ptr)[N]
where N would be a self-defining value (compile time constant). Which
do you really want?

Your following code deals with the second type. However, since the
first type allows you to step through the array more easily (less
typing), the second type is much less frequently used.
at older posts in this group, and tried a solution that looked
sensible, but it didn't work right. Here is a simple example of what
I'm trying to accomplish:

// I have a hardware peripheral that I'm trying to access
// that has two ports. Each port has 10 sequential
// registers. Create a structure definition that
// defines a single port.

typedef struct {
long long1;
long long2;
long long3;
long long4;
long long5;
long long6;
long long7;
long long8;
long long9;
long long10;
} volatile my_struct;

Doesn't the volatile need to be between the words typedef and struct
on the first line of the declaration?
// Create a pointer to an array of two structures
my_struct (*my_struct_ptr)[2];

This does define a pointer to an array of 2 struct.
#define PERIPHERAL_BASEADDR 0xA0000000

int main(int argc, char **argv)
{
// This is the syntax I came up with to initialize
// the pointer. Keep in mind that this line of code
// isn't even needed in this example to illustrate the
// behavior of the compiler with respect to addressing.
my_struct_ptr = (my_struct (*)[])PERIPHERAL_BASEADDR;

If you change the subscript from [] to [2] it should be syntactically
correct.
printf("&my_struct_ptr[0] = %08X\n",
&my_struct_ptr[0]);

Here you promise the argument corresponding to %X will have type int.
You actually pass the an argument that has type pointer to array of 2
struct. (The & and the [0] basically cancel each other.) This
invokes undefined behavior. If you want to print the value of a
pointer, use %p and cast the value to a void*.
printf("&my_struct_ptr[1] = %08X\n",
&my_struct_ptr[1]);

printf("sizeof(my_struct) = %x\n",
sizeof(my_struct));

sizeof evaluates to a size_t which need not be an int. Cast it if you
want to use %x.
printf("sizeof(my_struct_ptr[0]) = %x\n",
sizeof(my_struct_ptr[0]));

printf("sizeof(my_struct_ptr[1]) = %x\n",
sizeof(my_struct_ptr[1]));

printf("&(my_struct_ptr[0]->long1) = %08X\n",
&(my_struct_ptr[0]->long1));

printf("&(my_struct_ptr[0]->long10) = %08X\n",
&(my_struct_ptr[0]->long10));

printf("&(my_struct_ptr[1]->long1) = %08X\n",
&(my_struct_ptr[1]->long1));

printf("&(my_struct_ptr[1]->long10) = %08X\n",
&(my_struct_ptr[1]->long10));
}

Here is the output of the program:

&my_struct_ptr[0] = A0000000
&my_struct_ptr[1] = A0000050
sizeof(my_struct) = 28
sizeof(my_struct_ptr[0]) = 50
sizeof(my_struct_ptr[1]) = 50
&(my_struct_ptr[0]->long1) = A0000000
&(my_struct_ptr[0]->long10) = A0000024
&(my_struct_ptr[1]->long1) = A0000050
&(my_struct_ptr[1]->long10) = A0000074

It correctly calculates the size of the typedef'd structure, but it
reports the size of each element of the array as twice as big as it

No it doesn't. my_struct has a size of 40 bytes (hex 28).
my_struct_ptr is a pointer to an array of 2 struct. my_struct_ptr[0]
is the array it points to. Since the array has two elements, the size
of the array is 80 bytes (hex 50). Hence the question I asked at the
beginning. You want the pointer to point to an element of the array,
not the array itself.
should be. If there are three elements in the array, then the size of
each element is 3 times as big. In this example, long1 of the second

You never asked for the size of an element of the array. To do so you
would have to code my_struct_ptr[0][0].
element should be at address A0000028.

It is. You never asked for the address of that variable. The name
for that variable is my_struct_ptr[0][1].long1. Put an & in front to
get its address.

Your code - &(my_struct_ptr[1]->long1) - evaluates as follows:

my_struct_ptr is a pointer to an array of struct
my_struct_ptr[1] is the second array it points (the next array
past the first)
my_struct_ptr[1] is an array expression. As usual (when not the
operand of sizeof or &), the array expression evaluates to the address
of the first element of the array with type pointer to element. Since
the array is an array of struct, this evaluates to the address of the
first struct of the second array or &my_struct_ptr[1][0] with type
pointer to struct.
my_struct_ptr[1]->long1 is the first element of this struct which
is actually the third struct starting at your special address. The
first struct is my_struct_ptr[0][0], the second is [0][1], and [1][0]
is the third.
I am using the GCC compiler, but I don't think it is a bug in the
compiler. I tried it in Visual C++ and got the same results.

The "problem" is you chose to use a pointer to array rather than
pointer to first element of array.
I tried to use a pointer to a single structure and use it like an
array. That only half works because the compiler doesn't see it as an
array of structures and therefore you can't access the elements of the
structure and index as well.

Yes it can. Show your code so we can see what you did wrong.


Remove del for email
 
R

Rod Pemberton

Chris Torek said:
In general, I advise against making nameless structure types and
then giving them aliases. I suggest even more caution when mixing
"volatile" in. See <http://web.torek.net/torek/c/types2.html>.

CT:"[insert link to scopes and linkage rules once I write the html page]"

That would be nice.


CT:"One of the biggest drawbacks I find with C's typedef syntax is that it
mucks[sic] up C's declarations (and C's 'declaration mirrors use' syntax is
already one of C's most confusing features)."

Really?


CT:"With typedef names, however, we see only an ordinary identifier,
indistinguishable from any other ordinary identifier, ..."

(warning: sarcasm) What? You don't like the implicit "typedefname" keyword?
Isn't it the best feature of C? Ah, for want of two keywords, C isn't
LALR(1)...


CT:"...this (C89-specific) code fragment: 'void f(x);' Can you tell from
this code fragment whether x is a typedef name, or a variable name whose
type is defaulted to int?"

Implicit int versus type-specifier problem: C89, no. (But, C99, yes.)


CT:"For this reason, those who use typedefs almost invariably invent a
typographic convention (or several conventions) to make them stand out. If
we can tell at a glance that some identifier is a typedef-alias, the
syntactic problem vanishes. In my experince[sic], the three most common
conventions are:"

(spelling error)

CT(1):"Appending _t to the name, producing identifiers like uid_t,
pthread_t, and so on. (The T here stands for 'type'. Note that POSIX
reserves all such identifiers.)"

Never heard of that...

CT(2):"Using an initial capital letter for the identifier (provided, of
course, that initial capitals are never used for other purposes)."

Never heard of that... Oh, wait: Pascal programmers meet C...

CT(3):"Spelling the name in all-capitals, like Standard C's FILE type."

Seen that, and I don't really like it, except for FILE.


CT:"While I personally dislike typedef and am entirely willing to write out
the struct keyword every time,..."

Okay, _IF_ it existed, would you be willing to write out "typedefname"
everytime? How about this (using your examples):

#define typedefname ut
typedef int x;
int *a;
ut x *b; /* typedefname x *b */
int **p = &b;

void f(x); /* int x */
void f(ut x); /* typedefname x */

Wow, look at that... It's even portable:
#define ut

Now just add a keyword for terminated if and you've got LALR(1) C. In fact,
I'm injecting an implicit token where "ut" or "typedefname" is with
bison/flex grammars (one grammar rule change), and it _seems_ to be working
quite well... Determining where to inject was a bit difficult though. I'm
not sure if it's 100% accurate yet. I was trying to avoid passing
information from bison to flex.

CT:"Suppose we rewrite the earlier code fragment to use a typedef-name to
alias the incomplete structure type, and then use the alias in the function
prototypes: ... While the actual type-declaration still happens because of
the struct keyword, we now get a compiler diagnostic for the third line,
because the misspelled identifier is not a typedef-name"

Nifty.


CT:"...that it is the typedef keyword that defines the types, and attempt to
omit the structure tags, giving something like: ... which of course does not
work at all"

Confusing... Okay, when you said "attempt to omit the structure tags" you
were referring to the inner elements of the last two structures, not the
typedef-names for the last two structures. Dude, you named _everything_ the
same... including the stuff you weren't trying to point out as problematic.


CT:"Note that if you do use typedefs, and you avoid the situation I describe
as a 'bad idea' -- that is, you always avoid defining an inner-scope type
with the same name as some outer-scope type..."

Clarification is good, but three or four sentences late.



Rod Pemberton
 
A

Al Balmer

CT(1):"Appending _t to the name, producing identifiers like uid_t,
pthread_t, and so on. (The T here stands for 'type'. Note that POSIX
reserves all such identifiers.)"

Never heard of that...

Never heard of the convention, or never heard of the reservation? I've
seen the convention used for years. And it is a POSIX.1 reserved
namespace, "_t" as a suffix, in any context. I don't have the actual
standard handy, but it's in table 2-8 of Gallmeister,
"POSIX.4:programming for the Real World".
 
G

gcary

Barry said:
I am having trouble figuring out how to declare a pointer to an array
of structures and initializing the pointer with a value. I've looked

Clarify your terminology. The phrase pointer to an array is
frequently misused to mean pointer to the first element of the array.
For a type T, this would be coded as T *ptr. To be technically
correct, a pointer to an array of type T would be coded as T (*ptr)[N]
where N would be a self-defining value (compile time constant). Which
do you really want?

I do not believe T *ptr will work when trying to access the elements of
the structure if I use a syntax such as this: ptr[1]->long2;
So what I want is T (*ptr)[1], which will allow the type of syntax I
desire.
Doesn't the volatile need to be between the words typedef and struct
on the first line of the declaration?

Good point, I don't know the answer. What you say seems reasonable.
Since not all of the registers are actually volatile, maybe I should
place the volatile keyword only on those structure members that are
volatile.
Here you promise the argument corresponding to %X will have type int.
You actually pass the an argument that has type pointer to array of 2
struct. (The & and the [0] basically cancel each other.) This
invokes undefined behavior. If you want to print the value of a
pointer, use %p and cast the value to a void*.

I agree that it was sloppy and I should have cast it to something. I
didn't know about %p. I tried it on our system and it is unsupported.
It is a really simplified version of printf, so I'm not surprised.
Yes it can. Show your code so we can see what you did wrong.

What I said was I used a pointer to a single structure, not a structure
that has anything to do with an array.

typedef struct {
long long1;
long long2;
} my_struct;

my_struct *my_struct_ptr;

#define PERIPHERAL_BASEADDR 0xA0000000

int main(int argc, char **argv)
{
my_struct_ptr = (my_struct *)PERIPHERAL_BASEADDR;

xil_printf("&(my_struct_ptr[0]->long1) = %08X\r\n",
&(my_struct_ptr[0]->long1));
}

compiler output:
error: invalid type argument of `->'

Thanks for your help as well as everyone else. I've figured out the
syntax I need to accomplish what I need.

Regards,

Greg
 
K

Keith Thompson

Barry said:
I am having trouble figuring out how to declare a pointer to an array
of structures and initializing the pointer with a value. I've looked

Clarify your terminology. The phrase pointer to an array is
frequently misused to mean pointer to the first element of the array.
For a type T, this would be coded as T *ptr. To be technically
correct, a pointer to an array of type T would be coded as T (*ptr)[N]
where N would be a self-defining value (compile time constant). Which
do you really want?

I do not believe T *ptr will work when trying to access the elements of
the structure if I use a syntax such as this: ptr[1]->long2;
So what I want is T (*ptr)[1], which will allow the type of syntax I
desire.

No, you almost certainly want a pointer to an element of the array.
Just use "." rather than "->", since ptr[1] is a structure, not a
pointer:

#include <stdio.h>
int main(void)
{
typedef struct {
long long1;
long long2;
} T;
T arr[2] = { { 10, 20 },
{ 30, 40 } };
T *ptr = arr;
printf("ptr[1]->long2 = %ld\n", ptr[1].long2);
return 0;
}
 
G

gcary

Keith said:
No, you almost certainly want a pointer to an element of the array.
Just use "." rather than "->", since ptr[1] is a structure, not a
pointer:

#include <stdio.h>
int main(void)
{
typedef struct {
long long1;
long long2;
} T;
T arr[2] = { { 10, 20 },
{ 30, 40 } };
T *ptr = arr;
printf("ptr[1]->long2 = %ld\n", ptr[1].long2);
return 0;
}

You're right. Since I needed to create a pointer to an array of
structures, I led myself to believe I needed to use the "->" notation.

Thanks to everyone who got me set straight about what I was doing. I
guess there are at least two ways to skin this cat, but I think this
one is the simpler and more straightforward approach. Not as
mindbending.

Greg
 
J

Joe Wright

Chris, thanks for your help. Thanks for your advice about nameless
structure types. That makes some sense. I'll re-read your website
tomorrow when I'm more awake. About the volatile modifier, would you
recommend placing it on each of the elements of the structure rather
than the structure itself?

Please, what is your need for volatile? Is the structure and/or its
members changeable by things outside your program?
 
G

gcary

Joe said:
Please, what is your need for volatile? Is the structure and/or its
members changeable by things outside your program?

Joe,

Yes they are. The reason for the pointer to the structure is because
it is a hardware peripheral. Several of the registers are dynamic,
being changed by processes outside the software.

Greg
 
C

Chris Torek

[Background: the OP defined a structure that maps onto a hardware
register layout, e.g.:

struct foo_hw_regs {
int csr; /* control and status register */
int bar; /* bus address register */
int err; /* additional-error info register */
};

and needs to have set a pointer to point to the first of a series
of such registers, on a machine that has memory-mapped hardware
registers.]

... About the volatile modifier, would you recommend placing it
on each of the elements of the structure rather than the structure itself?

Actually, I prefer to attach it specifically to the pointer(s) that
point to the hardware registers, not to the structure at all.

As an example of why you might want to do this, consider hardware
on which simply *accessing* the registers clears them. (This was
pretty common in Ye Olden Dayse.) In order to work with this
hardware, you have to "grab a snapshot" of the registers involved,
and only then look at the bits -- something like:

void xyz_interrupt(void) {
volatile int *xyzreg = XYZREG_ADDR;
int state = *xyzreg;

... now test state&XYZ_DMA_ERR, state&XYZ_RESET, etc ...
}

Note that the "int state" is *not* volatile. In a sort of parallel
construction, if the XYZ device has a structure, we might write:

/* this function talks to the acutal hardware */
void xyz_hw_interface_function(volatile struct xyzreg *hw) {
... work with hw->whatever ...
}

but also write:

/* this function works with values that already have been read from,
or will be written to, the hardware */
void xyz_sw_func(struct xyzstate *state, struct xyzreg *sw) {
... work with sw->whatever ...
}

Then, at some point in the code, you simply copy between the
(non-volatile) "software" copy of the register values and the
(volatile) "hardware" copy.

(Of course, if your goal includes making the driver portable to
different hardware -- where the same device has the same registers
but in a different layout[%] -- then you end up having to separate
the state into "volatile, machine-and-hardware-specific" and
"non-volatile, hardware-specific but machine-independent" forms.
But this task usually comes later, after getting the driver to work
on one specific machine.

[%] I know some people think this is impossible, or at least "too
hard", but there are real, working counterexamples in NetBSD, for
instance. It does, admittedly, get ugly -- one has to use
accessor macros to talk to hardware registers, so that they can
be either memory- or I/O-mapped, for instance.)

[This specific hardware happens to have two copies of the register
structure, one right after the other.]
... I think you're saying that what I need to do is the
following:

my_struct (*mystruct_ptr)[1];

While this will work, it is unnecessary.

Consider:

char buf[6];
char *p;

p = &buf[0];

p[0] = 'a';
p[1] = 'r';
p[2] = 'r';
p[3] = 'a';
p[4] = 'y';
p[5] = 0;

We have just accessed an "array 6 of char" -- 6 sequential "char"s
-- with one "pointer to char". This is not a "pointer to array of
char", it is just a plain old "pointer to char". Nonetheless, it
points to an array -- or more precisely, it points to *the first
element of* an array, and such a pointer is "just as good" as a
pointer to the entire array, as long as you remember how big the
array is too.

Likewise, given some "array" of hardware registers at some address:

#define HW_REGS ((volatile struct hw_regs *)0x12345600)

we can point a pointer to the first element of that array:

volatile struct hw_regs *hw = HW_REGS;

and then access the entire array, provided we remember how big
it is:

hw[0].structmember = 42;
hw[1].structmember = 99;

Note that hw[0].field and hw->field mean exactly the same thing.
Likewise, *p and p[0] mean the same thing -- and in fact, instead
of either hw->structmember or hw[0].structmember, we could write
(*hw).structmember; but the parentheses are required here, since
without them, the expression parses as *(hw.structmember), which
is invalid (the "." operator requires that the item on its left
name a structure or union).

The tricky thing about this array stuff in C -- the part that seems
to confuse the most people the longest -- is that the "decay" from
array to pointer happens "only once" in any given expression.
Given "array N of T", we get "pointer to T"; but if T is itself an
array -- e.g., if we start with "array 10 of array 4 of int" -- we
stop there, and end up with "pointer to array 4 of int". The
"decay" is why pointers and arrays have interchangeable *uses* (but
are not the "same thing"); that it "only happens once" is why you
can only omit the first constant in array parameters:

void ok(double x[][5][2][3]) {
/* code */
}
void diagnostic_required(double x[][][2][3]) { /* ERROR */
}

Luckily, your hardware registers are just a single-level array,
not an array of arrays. So you can just use a simple, ordinary
pointer, not a "pointer to array".
 
D

Dave Thompson

CT:"One of the biggest drawbacks I find with C's typedef syntax is that it
mucks[sic] up C's declarations (and C's 'declaration mirrors use' syntax is
already one of C's most confusing features)."

Really?
Why 'sic'? Is this slang not sufficiently widespread? In en_US at
least, and I thought en_GB, 'mucks up' is slightly harsher than
'messes up' or 'soils' and slightly milder than 'screws up'.

FWIW, I agree (with CT) that declaration mirrors use has proven in
hindsight to have been a mistake (that we now are stuck with),
although I don't feel that typedef makes it much worse.
Okay, _IF_ it existed, would you be willing to write out "typedefname"
everytime? How about this (using your examples):

#define typedefname ut

I think you meant this the other way, i.e. the clumsier but less
intrusive typedefname would be standard and for this program (or
example) you are using a more convenient abbreviation.
typedef int x;
int *a;
ut x *b; /* typedefname x *b */
int **p = &b;

void f(x); /* int x */
void f(ut x); /* typedefname x */
FWIW, this was effectively the approach chosen by Fortran (90), I
believe the only other part of the algol clan to not put type (mostly)
_after_ name in declarations, if you let me keep Java in the C family.

It calls its equivalent of 'struct' (rather confusingly) 'derived
type' the keyword TYPE and defines one like:
TYPE FOO
REAL RELEMENT
INTEGER IELEMENT
END TYPE FOO
and then uses it like:
TYPE(FOO) :: ONEFOO, ANOTHERFOO

I believe this possibly more verbose than necessary approach is partly
because Fortran (still) has to deal with the legacy of the decisions
way back when for insignificant spaces and nonreserved keywords.

- David.Thompson1 at worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top