3

I am looking at some code about which I am puzzled.

This snippet is in the header file, RPI.h:

#define BCM2708_PERI_BASE  0x20000000
#define GPIO_BASE         (BCM2708_PERI_BASE + 0x200000) // GPIO controller 

// IO Access
struct bcm2835_peripheral {
    unsigned long addr_p;
    int mem_fd;
    void *map;
    volatile unsigned int *addr;
};

struct bcm2835_peripheral gpio = {GPIO_BASE};

extern struct bcm2835_peripheral gpio;

From the RPI.c file:

#include "RPI.h"

struct bcm2835_peripheral gpio = {GPIO_BASE};

I am puzzled by the line in both the .h and .c files:

struct bcm2835_peripheral gpio = {GPIO_BASE};

It looks to me that a new struct of type bcm2835_peripheral named gpio is being instantiated and set equal to GPIO_BASE. However, the struct has four, public members. Are they all being set to GPIO_BASE?

I only included the lines from the .h and .c files which were relevant. The lines are in the order they are in the original files.

dbush
  • 205,898
  • 23
  • 218
  • 273
user34299
  • 377
  • 2
  • 11

1 Answers1

10

When a struct or array is initialized, you don't have to give an initializer for every element.

For the initializers that are there, the fields are set in order, and any remaining fields for which there is no initializer are set to 0 for integer types and NULL for pointer types.

From section 6.7.9 of the C standard:

10 If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then:

if it has pointer type, it is initialized to a null pointer;

if it has arithmetic type, it is initialized to (positive or unsigned) zero;

— if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;

— if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;

...

21 If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

So in this case the addr_p field is set to GPIO_BASE, while mem_fd, map, and addr are set to 0, NULL, and NULL respectively.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    and **[dcl.init.aggr]** note 8 in C++ standard *If there are fewer initializer-clauses in the list than there are elements in the aggregate, then each element not explicitly initialized shall be initialized from its default member initializer (9.2) or, if there is no default member initializer, from an empty initializer list* – user4581301 Dec 03 '16 at 01:02
  • This particular usage (`gpio = {GPIO_BASE}`) seems to be poor style since it initializes the first object (whatever it may be), rather than explicitly stating what it wants to initialize. (It also caused enough confusion for this question to be asked.) Using a [designated initializer](http://stackoverflow.com/questions/1601201/c-struct-initialization-using-labels-it-works-but-how-documentation) such as `gpio = { .addr_p = GPIO_BASE }` would be more explicit. – e0k Dec 03 '16 at 02:22
  • @user34299 Did this answer your question? – dbush Dec 03 '16 at 20:53