C programming. "Using #include inside array initialization"

Hello again.. I just want to know if the syntax bellow is valid.. I tried to initialize an array with a file instead where are defined some assets, but I get an error at the end of the array where I put the semicolon saying 'Expected an expression'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*Assets.c file*/

#include "CompilerSettings.h"

#pragma warning(push, 3)
#include <stdbool.h>
#include <stdint.h>
#include <xaudio2.h>
#include "miniz.h"                  // Needed for decompress the archives
#pragma warning(pop)

#include "AssetsConfig.h"
#include "Assets.h"

typedef struct tagASSETS_LIST {
    ASSET_GROUP group;
    const char* name;
    void* pointer;
} ASSETS_LIST;

#define ASSET_ENTRY(group, name, pointer)   { group, name, pointer },

static const ASSETS_LIST assetsList[] = {
    #include "AssetsList.h"
}; // <- The error is here.. but not red underline

#undef ASSET_ENTRY 


.. And in the AssetsList.h I have the assets.. I'll post some of them but because they are too many but they look the same as syntax:

1
2
3
4
5
6
7
8
#pragma once

#define ASSET_ENTRY(group, name, pointer)

ASSET_ENTRY(CRITICAL_ASSETS, "Font.bmpx", &gFont)
ASSET_ENTRY(CRITICAL_ASSETS, "TransitionScreen.wav", &gSoundTransictionScreen)
ASSET_ENTRY(CRITICAL_ASSETS, "Overworld01.tmx", &gOverworld01.tileMap)
.. etc.


So if I don't define this in the header:
 
#define ASSET_ENTRY(group, name, pointer)  


The error that says 'Expected an expression' appears here at first ASSET_ENTRY. So by define the dummy again in the header, the error moves to Assets.c file at the end of the array where is the semicolon saying the same thing 'Expected an expression' What is wrong with it..? Doesn't sees the file or what is happening? I know I can move all those entries to the .c file to initialize, but I'm curious why this doesn't work, cause I'm sure I saw this once and I know it works. Thank you!
You'd help yourself and others if you create a minimal example that still reproduces your issue. I don't feel like guessing what the definition is for a bunch of the stuff in your post, like ASSET_GROUP, CRITICAL_ASSETS, gFont, etc. Creating a minimal reproducible example will help figure out what the problem is -- improve the signal-to-noise ratio, so to speak.

Here's something that might be useful to you: You can instruct the compiler to go through and output the code after it's done the first-stage preprocessing.

>gcc -E Assets.c > preprocessed.c
>gcc -Wall -Wextra -c preprocessed.c

(Visual Studio can do similar, see https://stackoverflow.com/questions/8978997/how-can-i-see-the-output-of-the-visual-c-preprocessor)

If you examine the preprocessed.c file, the compiler error you get will probably make more sense to you because everything will be in one file. Then, you can work backwards to figure out which macro substitution is at fault.

Here's an example of what my preprocessed file looked like when I removed all the noise and just put in enough information to make it compile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 1 "Assets.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "Assets.c"



typedef int ASSET_GROUP;

int gFont;
int gSoundTransictionScreen;

typedef struct tagASSETS_LIST {
    ASSET_GROUP group;
    const char* name;
    void* pointer;
} ASSETS_LIST;



static const ASSETS_LIST assetsList[] = {
# 1 "AssetsList.h" 1
       

{ 0, "Font.bmpx", &gFont },
{ 0, "TransitionScreen.wav", &gSoundTransictionScreen },
# 19 "Assets.c" 2
};
Last edited on
1
2
3
#pragma once

#define ASSET_ENTRY(group, name, pointer) 


I'd definitely remove these two lines from your header file.

You need to include the body of the header file no matter what for it to make sense.
pragma once might be messing with that, omitting the file completely, resulting in an empty array.

And you also need to ensure there is only one ASSET_ENTRY definition. The one on line 21 of your posted code looks good.
Okay.. I probably not show that example but just a simplified one. So I just create another project and just simple write:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* Dummy Example - This is main.c source file*/

#include <stdio.h>

void* g6x7Font = NULL;
void* gSoundTransictionScreen = NULL;

#define ASSET_ENTRY(name, ptr)	{ name, ptr },

// Asset structure
static const struct {
	const char* name;
	void* ptr;
} myAssetList[] = {
	#include "main.h"
};

#undef ASSET_ENTRY

int main(void) {
	// Doesn't matter here.. do something with assets
	return 0;
}


Then in the header:

1
2
3
4
5
6
/*main.h file*/

#pragma once

ASSET_ENTRY("6x7Font.bmpx", &g6x7Font)
ASSET_ENTRY("TransitionScreen.wav", &gSoundTransictionScreen)


If you compile this the compiler will compile and succeed. The only problem I was pointing out is that you WILL see errors even it compiles, like:
ASSET_ENTRY("6x7Font.bmpx", &g6x7Font)// <- 'Expected an expression' in the main .h at first entry
. Then you'll see another error just like this in the main.c here:

myAssetList[] = {
#include "main.h"
}; // <- 'Expected an expression' .. ? What ..?


So it's like it sees the list in the main.h and in the same time it doesn't. I tried this at a point:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Dummy Example - This is main.c source file*/

#include <stdio.h>

void* g6x7Font = NULL;
void* gSoundTransictionScreen = NULL;
void* empty = NULL;

#define ASSET_ENTRY(name, ptr)	{ name, ptr },

// Asset structure
static const struct {
	const char* name;
	void* ptr;
} myAssetList[] = {
	ASSET_ENTRY("dummy", &empty) // put a dummy initializer. If empty ..not accepted
	#include "main.h"
}; // <- now doesn't complain anymore.?? 

#undef ASSET_ENTRY

int main(void) {
	// Doesn't matter here.. do something with assets
	return 0;
}


Now it still complain in the header at first entry.. I added this:

1
2
3
4
5
6
7
8
/*main.h file*/

#pragma once

#define ASSET_ENTRY(name, ptr) // <- new line

ASSET_ENTRY("6x7Font.bmpx", &g6x7Font)
ASSET_ENTRY("TransitionScreen.wav", &gSoundTransictionScreen)


Now it doesn't make sense to define that again. but the error goes away. and I have left with one warning:
'ASSET_ENTRY': macro redefinition

And that is true.
I even removed the
#pragma once
like salem_c recommended and the
#define ASSET_ENTRY(name, ptr)
and it doesn't work either. If I do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Dummy Example - This is main.c source file*/

#include <stdio.h>

void* g6x7Font = NULL;
void* gSoundTransictionScreen = NULL;
void* empty = NULL;

#define ASSET_ENTRY(name, ptr)	{ name, ptr },

// Asset structure
static const struct {
	const char* name;
	void* ptr;
} myAssetList[] = {
	ASSET_ENTRY("6x7Font.bmpx", &g6x7Font)
        ASSET_ENTRY("TransitionScreen.wav", &gSoundTransictionScreen)
};

#undef ASSET_ENTRY

int main(void) {
	// Doesn't matter here.. do something with assets
	return 0;
}


This works.. and not using the inclusion of the main.h, but that defeats the purpose as the list is quite big.
Forgot to add .. I use VS2019 as IDE so Yes I did close the project, remove the .vs folder as sometimes the intelliSense is not as intelli at all, and reopen , recompile and the errors still there, so is not a compile bug so to say.
In assets.c remove L21 & L27

In assetslist.h replace L3 with

#define ASSET_ENTRY(group, name, pointer) { group, name, pointer }

Then L5 onwards etc become eg
ASSET_ENTRY(CRITICAL_ASSETS, "Font.bmpx", &gFont),

Note that if you leave the terminating , in the ASSET_ENTRY definition then after the last usage of ASSET_ENTRY you'll need to have another value otherwise you have a 'dangling' , with nothing following.



Okay seeplus.. but if the macro you suggest
In assetslist.h replace L3 with

#define ASSET_ENTRY(group, name, pointer) { group, name, pointer }

At the end you'll gave no
,
comma because it will put at each line including the last one and that is true will cause an error because the compiler was complaining with
'Expected an expression'
for that reason as I don't add anything after
,
and if I don't add no
,
tothe macro as you mentioned I will have no
,
comma for all lines and will cause an error as well.. right?
Well I'm not at my PC right now to test it, but if you say that will work..well can't wait to change that and see it working at last :)

EDITED
I'm sorry 'seeplus' about the long comment.. I just realise now that you added a comma after the "ASSET_ENTRY(CRITICAL_ASSETS, "Font.bmpx", &gFont),"
Last edited on
Or.. I can let that macro:
#define ASSET_ENTRY(group, name, pointer) { group, name, pointer }, and ad that comma at the end, and in the Assets.c
1
2
3
4
static const ASSETS_LIST assetsList[] = {
    #include "AssetsList.h"
    { CRITICAL_ASSETS, "dymmy", &unused } // <- no ',' comma at the last one
};


Will this work .. ?
Okay.. I tried to define
#define ASSET_ENTRY(group, name, pointer) { group, name, pointer }
.. then I put a
,
after all
ASSET_ENTRY
in the header and delete L21 & L27 in assets.c. I get an error at the first
ASSET_ENTRY(CRITICAL_ASSETS, "6x7Font.bmpx", &g6x7Font),
in the header that says 'Expected a declaration'. :|
Last edited on
Do what Ganado suggested above and obtain the source after the pre-processing to see exactly what is the source the compiler is actually trying to compile.

Note that you don't put a comma after the last ASSET_ENTRY.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void* g6x7Font = ((void *)0);
void* gSoundTransictionScreen = ((void *)0);

static const struct {
	const char* name;
	void* ptr;
} myAssetList[] = {

#pragma once

{ "6x7Font.bmpx", &g6x7Font },
{ "TransitionScreen.wav", &gSoundTransictionScreen }

};

int main(void) {
	
	return 0;
}


Did that and I found this in the ".i" file. Well all looks good .. not the #pragma once.. I delete that and recompile the .c file and it still there.
Okay .. I was reopen the same file.. not deleted the #pragma once.. and it looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void* g6x7Font;
void* gSoundTransictionScreen;



static const struct {
	const char* name;
	void* ptr;
} myAssetList[] = {
	




{ "6x7Font.bmpx", &g6x7Font },
{ "TransitionScreen.wav", &gSoundTransictionScreen }

};


int main(void) {
	
	return 0;
}


At first .. this looks okay .. I mean including the header it includes correctly the entries.. and still complains if I build and compile.

The source file main.c
1
2
3
4
5
6
7
// Asset structure
static const struct {
	const char* name;
	void* ptr;
} myAssetList[] = {
	#include "main.h"
}; // <- 'expected an expression' 


And.. in the header
1
2
3
4
#define ASSET_ENTRY(name, ptr)	{ name, ptr }

ASSET_ENTRY("6x7Font.bmpx", &g6x7Font), // <- ;expected a declaration'
ASSET_ENTRY("TransitionScreen.wav", &gSoundTransictionScreen)
Last edited on
If that's what your pre-processed source file looks like, then I don't know what the issue is, sorry... what you posted is completely valid C code, albeit it's odd that you are taking the address of a void* pointer.

Just one more thing: Is that an IntelliSense error, or truly a compiler error? Sometimes, IntelliSense can throw bad errors, but they aren't truly compiler errors. Just a thought.

Also, regarding the discussion about trailing commas: I'm 99% sure trailing commas in arrays are legal in C, and 100% sure that they are legal in C++.
Last edited on
Do you happen to have that brain damage known as "precompiled headers" turned on?

I'd suggest turning it off.

And FFS stop using #pragma once with this header file containing your array initialisation.

Last edited on
Hello again and to respond both Ganado and salem_c.. I have a post if you scroll up when I said I closed the program and go to the folder, deleted the .vs folder, reopen the project and full recompile having the option
precompiled headers
turned off and the errors are still there. So at this point a believe is not anymore a
IntelliSense
error. Then if the void pointers I declare is a problem you can further simplify my second example where you told me to show a minimal working one.. which I did.. and make the structure have only 1 member just a string that I called
name
.. and delete all those pointers as well in the macro.
EDITED: Those void pointers were declared just for the sake of the example, otherwise the compiler will complain not knowing what the
g6x7Font
is. And still doing that same errors appears. Also I did delete the
#pragma once
from the header and what to see errors are still there. Guys regarding what any of you said to do, I did.. and I'm not pretend to be more good then anyone here.. what I want to say.. the program is valid C (yes).. and it compiles ..I wrote even that somewhere in my post.. but visually those are still there red underlined and in the error window underneath complaining about it that's it. So question: is it normal that a program compiles
works
and the errors still there.. cause for my eye doing everything okay..and still complain that bothers. And that's why I wanted to hear your opinion about it. Thank you.
Last edited on
Ignore intellisense.

Or better yet, turn it off.

Trust me, you'll be a better programmer once you throw away these training wheels.

If that's the only thing wrong, it's because it barfs on failing to see a comma at the end of the #include. It is too stupid to realise what is going on.

It only matters whether it compiles or not (which apparently, it does).

Yup.. it is. Okay this being said.. I'll pass over and mark this as solved. Because whatever I do it will throw that error no matter what.. which is not. So I'll trust what I did and your opinion. So.. thank you very much for the answers. Until next time.. cheers :)
Registered users can post here. Sign in or register to post.