Re: Need Help Declaring a Pointer to an Array of Structures



[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.]

In article <1155268505.642345.120300@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
<gcary@xxxxxxxxxxx> wrote:
... 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".
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.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.
.



Relevant Pages

  • Re: about clock register setting
    ... beitman AT applieddata DOT net ... You have a pointer to the structure ... of the hardware ... The registers are defined in the PXA270 Developer's Manual where you ...
    (microsoft.public.windowsce.platbuilder)
  • Re: about clock register setting
    ... The pointer to the stucuture is mapped to the base address of some part ... of the hardware ... The registers are defined in the PXA270 Developer's Manual where you can ... // pCLKRegs is a Clock manager's address and cccr is Core Clock ...
    (microsoft.public.windowsce.platbuilder)
  • Re: about clock register setting
    ... The pointer to the stucuture is mapped to the base address of some part ... of the hardware ... The registers are defined in the PXA270 Developer's Manual where you can ... // pCLKRegs is a Clock manager's address and cccr is Core Clock ...
    (microsoft.public.windowsce.platbuilder)
  • Re: Insufficient guarantees for null pointers?
    ... there in order to allow a simple definition of the semantics without requiring a global linear address space, and to allow efficient implementation of small arrays inside big objects on hardware that doesn't directly support the linear view of big objects that C requires. ... The semantics of *valid* pointer operations are simple and can be easily described in terms of the linear address sub-space that each C object is required to look like; it's the restrictions on validity of pointer math that are tricky and unclear and the subject of this subthread. ... It would still be a good idea for the language spec to try to make array overflows undefined behaviour, in order to allow implementations to detect them and complain. ...
    (comp.std.c)
  • Re: a history question
    ... >> I thought array indexing in C is just syntactic sugar around pointer ... index registers but pointers had to compete with other data (sometimes ... > of Fortran pointers, even without bounds checking, is somewhat ...
    (comp.lang.fortran)