Page 1 of 1

Global struct array invalid outside main

Posted: Sat Jun 22, 2024 1:14 pm
by MaxOfGales
Hello fellow devkiters,

I'm new to the GBA development scene and have run across a problem when trying to access an array of structs across multiple .c files.

Given the following structure sprite.h/sprite.c defines my Sprite struct, buffer.h/buffer.c defines a fixed size array of Sprites.
This array is valid in main.c but invalid in sprite.c (or any other .c file/object).
Further testing of an array of shorts works as expected and is valid across any .c file.

Any help to fill in the gap of knowledge I'm missing would be most appreciated :D

Here is my code below, my Makefile is boilerplate from example\gba\template

sprite.h

Code: Select all

#ifndef _SPRITE_
#define _SPRITE_

#include "global.h"

typedef struct Sprite
{	
    u16 sliceCount;
    const Rect* pSlices;
    const u16 *map;
} Sprite;

void sprite_make(const u16 *map, const Rect* pSlices, const u16 sliceCount, Sprite* pOutSprite);
#endif
sprite.c

Code: Select all

#include "sprite.h"
#include "buffer.h"

void sprite_make(const u16 *map, const Rect* pSlices, const u16 sliceCount, Sprite* pOutSprite)
{
    // Invlaid pOutSprite but valid g_spriteCount and g_tmp  
    pOutSprite = &g_spriteBuffer[g_spriteCount++];

    pOutSprite->map = map;
    pOutSprite->pSlices = pSlices;
    pOutSprite->sliceCount = sliceCount;   
}
buffer.h

Code: Select all

#ifndef _GAMEBUFFERS_
#define _GAMEBUFFERS_

#include "global.h"
#include "sprite.h"

#define SPRITE_BUFFER_SIZE 10

// Valid in main.c invalid in sprite.c
extern Sprite g_spriteBuffer[];
extern u16 g_spriteCount;

// Works as expected valid from both sprite.c and main.c
extern u16 g_tmp[];
#endif
buffer.c

Code: Select all

#include "buffer.h"

Sprite g_spriteBuffer[SPRITE_BUFFER_SIZE];
u16 g_spriteCount = 0;
u16 g_tmp[] = {1, 3, 5 , 6};

Re: Global struct array invalid outside main

Posted: Thu Aug 29, 2024 1:22 am
by Fighter19
This would be a C question, not really a GBA question, as such I think a general C forum would be more suited for this,
with more people available and willing to answer that question.

Your code compiles and links to me, after I add a definition of a Rect. Which I suspect is the main reason.
However it doesn't make much sense to me, to pass the constructed Sprite via the arguments of the function prototype.
To get the new Sprite obtained from the Sprite Pool (a more suitable name than buffer),
you need to pass out the Sprite pointer. You can either do this via the return value (which I suggest you use in this case),
or do it via a "reference" to a pointer. In which case you need to specify Sprite** (I'd discourage that).
Specifying it in the argument list is not enough, because values in the argument list are only copies in C.

Furthermore an implicit coding convention is to put the object, that is being modified or initialized first in the argument list.
Other than that, please next time include the exact output from the compiler, so people can tell more easily what's going on.

This is the version, that I ensured works:

main.c:

Code: Select all

#include <stddef.h>
#include "sprite.h"

int main()
{
    Sprite *pSprite = NULL;
    sprite_make(NULL, NULL, 16, &pSprite);
    // Now pSprite contains a valid pointer to a Sprite object
}
sprite.c:

Code: Select all

#include "sprite.h"
#include "buffer.h"

void sprite_make(const u16 *map, const Rect* pSlices, const u16 sliceCount, Sprite** pOutSprite)
{
    // Allocate a sprite from the sprite pool
    Sprite *pNewSprite = &g_spriteBuffer[g_spriteCount++];

    pNewSprite->map = map;
    pNewSprite->pSlices = pSlices;
    pNewSprite->sliceCount = sliceCount;
    
    *pOutSprite = pNewSprite;
    
    // Consider returning Sprite* instead of passing Sprite as reference/pointer, arguments in C are always copied, not referenced, meaning changes to pOutSprite would be lost without another pointer
}
sprite.h

Code: Select all

#ifndef _SPRITE_
#define _SPRITE_

#include "global.h"

typedef struct Sprite
{
    u16 sliceCount;
    const Rect* pSlices;
    const u16 *map;
} Sprite;

void sprite_make(const u16 *map, const Rect* pSlices, const u16 sliceCount, Sprite** pOutSprite);
#endif
And

Code: Select all

typedef struct Rect
{
    u16 left;
    u16 right;
    u16 top;
    u16 bottom;
} Rect;
defined in global.h, because that's the only other file through in which it could be defined given the three header files.

Re: Global struct array invalid outside main

Posted: Mon Oct 07, 2024 9:51 pm
by MaxOfGales

Sorry for the late reply! I only just got time to continue my project!

Thank you for finding my silly noob mistake! Your help and detailed answer is very much appreciated! :D