Need Help Declaring a Pointer to an Array of Structures

Discussion in 'C Programming' started by gcary@trancer.com, Aug 11, 2006.

  1. Guest

    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
    , Aug 11, 2006
    #1
    1. Advertising

  2. Chris Torek Guest

    In article <>
    <> wrote:
    >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
    "volatile" in. See <http://web.torek.net/torek/c/types2.html>.
    (Neither of these is the problem though.)

    >// 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>.
    --
    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.
    Chris Torek, Aug 11, 2006
    #2
    1. Advertising

  3. Guest

    Chris Torek wrote:
    > In article <>
    > <> wrote:
    > >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
    > "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
    , Aug 11, 2006
    #3
  4. On 10 Aug 2006 16:16:04 -0700, wrote:

    >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
    Barry Schwarz, Aug 11, 2006
    #4
  5. "Chris Torek" <> wrote in message
    news:...
    > In article <>
    > <> wrote:
    > >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
    > "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
    Rod Pemberton, Aug 11, 2006
    #5
  6. Al Balmer Guest

    On Fri, 11 Aug 2006 03:19:54 -0400, "Rod Pemberton"
    <> wrote:

    >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".

    --
    Al Balmer
    Sun City, AZ
    Al Balmer, Aug 11, 2006
    #6
  7. Guest

    Barry Schwarz wrote:
    > On 10 Aug 2006 16:16:04 -0700, wrote:
    >
    > >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.

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


    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
    , Aug 11, 2006
    #7
  8. writes:
    > Barry Schwarz wrote:
    >> On 10 Aug 2006 16:16:04 -0700, wrote:
    >>
    >> >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;
    }

    --
    Keith Thompson (The_Other_Keith) <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.
    Keith Thompson, Aug 11, 2006
    #8
  9. Guest

    Keith Thompson wrote:
    > 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
    , Aug 11, 2006
    #9
  10. Joe Wright Guest

    wrote:
    > Chris Torek wrote:
    >> In article <>
    >> <> wrote:
    >>> 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
    >> "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?
    >


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

    --
    Joe Wright
    "Everything should be made as simple as possible, but not simpler."
    --- Albert Einstein ---
    Joe Wright, Aug 12, 2006
    #10
  11. Guest

    Joe Wright wrote:
    > 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
    , Aug 14, 2006
    #11
  12. Chris Torek Guest

    [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 <>
    <> 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.
    Chris Torek, Aug 20, 2006
    #12
  13. On Fri, 11 Aug 2006 03:19:54 -0400, "Rod Pemberton"
    <> wrote:

    > <snip> <http://web.torek.net/torek/c/types2.html>.


    > 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
    Dave Thompson, Sep 4, 2006
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. tweak
    Replies:
    14
    Views:
    2,767
    Eric Sosman
    Jun 11, 2004
  2. Replies:
    12
    Views:
    1,015
    Keith Thompson
    Sep 17, 2005
  3. Alfonso Morra
    Replies:
    11
    Views:
    703
    Emmanuel Delahaye
    Sep 24, 2005
  4. , India

    pointer to an array vs pointer to pointer

    , India, Sep 20, 2011, in forum: C Programming
    Replies:
    5
    Views:
    442
    James Kuyper
    Sep 23, 2011
  5. sonic
    Replies:
    5
    Views:
    87
Loading...

Share This Page