Initializing typedef struct from C library properl

2019-08-12 21:15发布

问题:

I want to include a library in my C++ project (controls RGB LED strips on the Raspberry Pi). Importing the library is working fine but I have quite the issue with properly initializing some structs. I'm pretty lost where to even find the proper syntax, I did a lot of googling but didn't get very far.

What I want to at first is getting the sample application going that comes with the library. See: https://github.com/richardghirst/rpi_ws281x/blob/master/main.c

My main issue is this. How do I do what is done below the C++ way?

ws2811_t ledstring =
{
    .freq = TARGET_FREQ,
    .dmanum = DMA,
    .channel =
    {
        [0] =
        {
            .gpionum = GPIO_PIN,
            .count = LED_COUNT,
            .invert = 0,
            .brightness = 255,
        },
        [1] =
        {
            .gpionum = 0,
            .count = 0,
            .invert = 0,
            .brightness = 0,
        },
    },
};

The way this is initialized is C specific and doesn't compile in any current C++ standard. See: Why does C++11 not support designated initializer list as C99? So far I only ever used my own structs and also never used typedef, so I'm just confused the way structs are defined here.

The struct(s) that gets initialized above is defined in this way. See: https://github.com/richardghirst/rpi_ws281x/blob/master/ws2811.h

typedef struct
{
    int gpionum;                          //< GPIO Pin with PWM alternate function
    int invert;                           //< Invert output signal
    int count;                            //< Number of LEDs, 0 if channel is unused
    int brightness;                       //< Brightness value between 0 and 255
    ws2811_led_t *leds;                   //< LED buffers, allocated by driver based on count
} ws2811_channel_t;

typedef struct
{
    struct ws2811_device *device;                //< Private data for driver use
    uint32_t freq;                               //< Required output frequency
    int dmanum;                                  //< DMA number _not_ already in use
    ws2811_channel_t channel[RPI_PWM_CHANNELS];
} ws2811_t;

What I tried was this:

ws2811_led_t matrix[WIDTH][HEIGHT];
ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};

That compiles but results in a malloc error when I come to actually "render" to the LED strip:

int x, y;

for (x = 0; x < WIDTH; x++)
{
    for (y = 0; y < HEIGHT; y++)
    {
        cout << "LEDs size: " << (y * WIDTH) + x << endl;
        ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];
    }
}

Results in this error message after the loop construct finishes:

malloc(): memory corruption (fast): 0x021acaa8

回答1:

You should be able to use use following initializer:

ws2811_t ledstring =
{
    nullptr,
    TARGET_FREQ,
    DMA,
    {
        { GPIO_PIN, 0, LED_COUNT, 255 },
        { 0 }
    }
};


回答2:

This line

ledstring.channel[0].leds[(y * WIDTH) + x] = matrix[x][y];

is almost certainly the cause of the memory corruption, as that can only happen by either a buffer overrun or dereferencing an invalid (but non-NULL) pointer.

I see some problems in this code

ws2811_channel_t channel0 = {GPIO_PIN,LED_COUNT,0,255,*matrix};
ws2811_t ledstring = {nullptr,TARGET_FREQ,DMA,channel0};

First, in the initializer for channel0 you are setting the leds field to the contents of matrix[0][0] rather than its address. You need to change the final initializer to be simply matrix.

Next, you are initializing channel0.leds to point to the two dimensional array matrix, but treating it as a single dimensional array in ledstring.channel[0].leds[(y * WIDTH) + x]. This should probably be ledstring.channel[0].leds[x][y].

Finally, the last initializer for ledstring should probably be {channel0} for clarity. That's not a big issue, but it allows you to initialize more than one entry in the array.



标签: c++ c struct