Question About Structure Initialization For REAL Expert

B

Bill Reid

OK, let's say that have a function menu structure declaration
like this (since I basically do):

typedef struct function_item {
char *descrip;
void(*function)(void);
} t_function_item;

typedef struct function_menu {
unsigned short num_items;
unsigned short default_item;
char *title_prompt;
t_function_item *function_items;
} t_function_menu;

Now sometimes (really just about all the time) I want to initialize it to
literal values. So this is how I do it (sort of) for a local function that
selects
a function and runs it (code that doesn't illustrate the question elided):

void my_function_1(void) {
}

void my_function_2(void) {
}

unsigned short run_function_menu(t_function_menu *function_menu) {
}

void select_function(void) {
static t_function_menu my_function_menu=
{0,0,"My Function Menu"};
static t_function_item my_function_items[]={
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}};
my_function_menu.function_items=my_function_items;

run_function_menu(&my_function_menu);
}

My question is: for some reason if I try to initialize the menu
structure in one fell swoop, with what seems to me to be a legal
initialization, like this:

static t_function_menu my_function_menu=
{0,0,"My Function Menu",(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}};

I just get a bunch of syntax errors, but to me, the above seems
to be functionally identical to what I actually have to do as shown in
the select_function() example to get the thing to work...why am I
getting the errors, and IS there some way to initialize such a structure
in one initialization assignment? What am I missing here?
 
I

Ian Collins

Bill Reid wrote:

I just get a bunch of syntax errors, but to me, the above seems
to be functionally identical to what I actually have to do as shown in
the select_function() example to get the thing to work...why am I
getting the errors, and IS there some way to initialize such a structure
in one initialization assignment? What am I missing here?
What errors?

The code looks fine. Are you using a C99 compiler?
 
C

CBFalconer

Ian said:
Bill Reid wrote:



What errors?

The code looks fine. Are you using a C99 compiler?

--
+-------------------+ .:\:\:/:/:.
| PLEASE DO NOT F :.:\:\:/:/:.:
| FEED THE TROLLS | :=.' - - '.=:
| | '=(\ 9 9 /)='
| Thank you, | ( (_) )
| Management | /`-vvv-'\
+-------------------+ / \
| | @@@ / /|,,,,,|\ \
| | @@@ /_// /^\ \\_\
@x@@x@ | | |/ WW( ( ) )WW
\||||/ | | \| __\,,\ /,,/__
\||/ | | | jgs (______Y______)
/\/\/\/\/\/\/\/\//\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
==============================================================

fix (vb.): 1. to paper over, obscure, hide from public view; 2.
to work around, in a way that produces unintended consequences
that are worse than the original problem. Usage: "Windows ME
fixes many of the shortcomings of Windows 98 SE". - Hutchinson
 
R

rahul

    static t_function_menu my_function_menu=
    {0,0,"My Function Menu",(t_function_item []){
    {"My Function 1",my_function_1},
    {"My Function 2",my_function_2},
    {NULL,NULL}}};
Compound literals allowed only in C99. A C99 compiler should not
complain.
 
H

Harald van Dijk

Bill Reid wrote:

[[ context:

static t_function_menu my_function_menu=
{0,0,"My Function Menu",(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}};

in a function ]]
What errors?

The code looks fine. Are you using a C99 compiler?

A C99 compiler is supposed to complain for the code Bill posted. It's not
supposed to treat this as a syntax error, but it is supposed to complain
about this, and it is extremely likely to make this an error anyway. You
can't initialise a static object using a pointer to an auto object.
 
I

Ian Collins

Harald said:
Bill Reid wrote:

[[ context:

static t_function_menu my_function_menu=
{0,0,"My Function Menu",(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}};

in a function ]]
What errors?

The code looks fine. Are you using a C99 compiler?

A C99 compiler is supposed to complain for the code Bill posted. It's not
supposed to treat this as a syntax error, but it is supposed to complain
about this, and it is extremely likely to make this an error anyway. You
can't initialise a static object using a pointer to an auto object.

Which auto object?
 
H

Harald van Dijk

Harald said:
Bill Reid wrote:

[[ context:

static t_function_menu my_function_menu=
{0,0,"My Function Menu",(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}};

in a function ]]
The code looks fine. Are you using a C99 compiler?

You can't initialise a static object using a pointer to an auto
object.

Which auto object?

(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}

A compound literal in a function definition has automatic storage
duration. There is no exception for initialisation.
 
B

Ben Bacarisse

Bill Reid said:
OK, let's say that have a function menu structure declaration
like this (since I basically do):

typedef struct function_item {
char *descrip;
void(*function)(void);
} t_function_item;

typedef struct function_menu {
unsigned short num_items;
unsigned short default_item;
char *title_prompt;
t_function_item *function_items;
} t_function_menu;

Now sometimes (really just about all the time) I want to initialize it to
literal values. So this is how I do it (sort of) for a local function that
selects
a function and runs it (code that doesn't illustrate the question elided):

void my_function_1(void) {
}

void my_function_2(void) {
}

unsigned short run_function_menu(t_function_menu *function_menu) {
}

void select_function(void) {
static t_function_menu my_function_menu=
{0,0,"My Function Menu"};
static t_function_item my_function_items[]={
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}};
my_function_menu.function_items=my_function_items;

run_function_menu(&my_function_menu);
}

My question is: for some reason if I try to initialize the menu
structure in one fell swoop, with what seems to me to be a legal
initialization, like this:

static t_function_menu my_function_menu=
{0,0,"My Function Menu",(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}};

I just get a bunch of syntax errors, but to me, the above seems
to be functionally identical to what I actually have to do as shown in
the select_function() example to get the thing to work...why am I
getting the errors,

The errors are due to the fact that you can't initialise a pointer
just by starting a new set of {}s.
and IS there some way to initialize such a structure
in one initialization assignment?

You have two options. (1) reverse the order like this:

static t_function_item my_function_items[] = {
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
};
static t_function_menu my_function_menu = {
(sizeof my_function_items / sizeof my_function_items[0]) - 1, 0,
"My Function Menu", my_function_items
};

or (2) use C99 compound literals and make the menu automatic rather
than static like this:

t_function_menu my_function_menu = {
2, 0, "My Function Menu",
(t_function_item[]){
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
}
};

There are other options. In C99 you can use method (1) and remove the
static storage class.
 
B

Ben Bacarisse

rahul said:
    static t_function_menu my_function_menu=
    {0,0,"My Function Menu",(t_function_item []){
    {"My Function 1",my_function_1},
    {"My Function 2",my_function_2},
    {NULL,NULL}}};
Compound literals allowed only in C99. A C99 compiler should not
complain.

Yes it should (at last I think it should) -- the object is static.
You can just make the whole menu automatic (see my reply).
 
B

Ben Bacarisse

Ben Bacarisse said:
"Bill Reid" <[email protected]> writes:
static t_function_menu my_function_menu=
{0,0,"My Function Menu",(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}};

I just get a bunch of syntax errors, but to me, the above seems
to be functionally identical to what I actually have to do as shown in
the select_function() example to get the thing to work...why am I
getting the errors,

The errors are due to the fact that you can't initialise a pointer
just by starting a new set of {}s.

I missed the () introducing a compound literal. Curiously the rest of
my answer is correct and helpful!

The errors will either be (a) not using a C99 compiler or (b) the
correct complaint that a static is being initialised with a compound
literal.
 
B

Bill Reid

OK, the bottom line seems to have something to do with
the specific "standard" that my compiler complies with, which
in my case is problematic, since it's kind of all over the map
(it uses SOME C99 stuff as "special extensions"), and I
didn't know that the type of initialization I was asking about
was only supported in C99...but let's see what my options
actually are:

Ben Bacarisse said:
Bill Reid said:
OK, let's say that have a function menu structure declaration
like this (since I basically do):

typedef struct function_item {
char *descrip;
void(*function)(void);
} t_function_item;

typedef struct function_menu {
unsigned short num_items;
unsigned short default_item;
char *title_prompt;
t_function_item *function_items;
} t_function_menu;

Now sometimes (really just about all the time) I want to initialize it to
literal values. So this is how I do it (sort of) for a local function that
selects
a function and runs it (code that doesn't illustrate the question elided):

void my_function_1(void) {
}

void my_function_2(void) {
}

unsigned short run_function_menu(t_function_menu *function_menu) {
}

void select_function(void) {
static t_function_menu my_function_menu=
{0,0,"My Function Menu"};
static t_function_item my_function_items[]={
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}};
my_function_menu.function_items=my_function_items;

run_function_menu(&my_function_menu);
}

My question is: for some reason if I try to initialize the menu
structure in one fell swoop, with what seems to me to be a legal
initialization, like this:

static t_function_menu my_function_menu=
{0,0,"My Function Menu",(t_function_item []){
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}}};

I just get a bunch of syntax errors, but to me, the above seems
to be functionally identical to what I actually have to do as shown in
the select_function() example to get the thing to work...why am I
getting the errors,

The errors are due to the fact that you can't initialise a pointer
just by starting a new set of {}s.

But it depends on the "standard", right?
and IS there some way to initialize such a structure
in one initialization assignment?

You have two options. (1) reverse the order like this:

static t_function_item my_function_items[] = {
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
};
static t_function_menu my_function_menu = {
(sizeof my_function_items / sizeof my_function_items[0]) - 1, 0,
"My Function Menu", my_function_items
};

OK, that works...and you even added a way to automatically
determine the number of items! Of course that element is actually
anachronistic and not really used anymore since I count the items
for error-checking user input in run_function_menu() by performing
the item display loop until I hit NULL...
or (2) use C99 compound literals and make the menu automatic rather
than static like this:

t_function_menu my_function_menu = {
2, 0, "My Function Menu",
(t_function_item[]){
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
}
};

Yeah, I can't do that with this compiler, but is there some difference
in C99 related to automatic initializations versus static? I'm using static
because if don't, when I do this call after the initialization:

run_function_menu(&my_function_menu);

I get a whole bunch of nothing...assuming run_function_menu()
just displays the menu; even worse is what happens when I do what
I really do (sort of, again abbreviated):

if((menu_choice=run_function_menu(&my_function_menu))!=0)
my_function_items[menu_choice-1].function();
There are other options. In C99 you can use method (1) and remove the
static storage class.

Yeah, for a local initialization I guess I can't do that with this
compiler...

Of course, the goal of all of this is to make creating, assembling,
and running menus to select ANYTHING as simple and fool-proof and
non-redundant as possible, as well as allow conditional compilation
for either a "terminal" application or a GUI (for a GUI, run_function_menu()
extracts the item descriptions into a string list to populate a pull-down
or other style of menu accessed by an external pointer to the menu
object, and returns the user menu selection).
 
B

Ben Bacarisse

Bill Reid said:
or (2) use C99 compound literals and make the menu automatic rather
than static like this:

t_function_menu my_function_menu = {
2, 0, "My Function Menu",
(t_function_item[]){
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
}
};

Yeah, I can't do that with this compiler, but is there some difference
in C99 related to automatic initializations versus static? I'm using static
because if don't, when I do this call after the initialization:

run_function_menu(&my_function_menu);

I get a whole bunch of nothing

Hmm... are you using lcc-win32? This program:

#include <stdio.h>
#include <stdlib.h>

typedef struct function_item {
const char *descrip;
void(*function)(void);
} t_function_item;

typedef struct function_menu {
unsigned short num_items;
unsigned short default_item;
const char *title_prompt;
t_function_item *function_items;
} t_function_menu;

void my_function_1(void)
{
printf("in %s()\n", __func__);
}

void my_function_2(void)
{
printf("in %s()\n", __func__);
}

void run_function_menu(t_function_menu *function_menu, int item)
{
if (item < 0 || item >= function_menu->num_items)
item = function_menu->default_item;
printf("Do #%d %s: ", item, function_menu->function_items[item].descrip);
function_menu->function_items[item].function();
}

int main(int argc, char **argv)
{
t_function_menu my_function_menu = {
2, 0, "My Function Menu",
(t_function_item[]){
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
}
};
run_function_menu(&my_function_menu, argc > 1 ? atoi(argv[1]) : 0);
return 0;
}

runs fine using gcc but gives a segmentation fault using lcc-win32.
Yeah, for a local initialization I guess I can't do that with this
compiler...

It looks like a general bug in the way structs get initialised to me.
Take this, for example:

#include <stdio.h>

int main(void)
{
int array[] = { 1, 2, 3 };
struct s {
int n;
int *items;
} s = { 3, array };
printf("%p %p\n", (void *)array, (void *)s.items);
return 0;
}

s.items does not get initialised.
 
B

Bill Reid

Ben Bacarisse said:
Bill Reid said:
or (2) use C99 compound literals and make the menu automatic rather
than static like this:

t_function_menu my_function_menu = {
2, 0, "My Function Menu",
(t_function_item[]){
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
}
};

Yeah, I can't do that with this compiler, but is there some difference
in C99 related to automatic initializations versus static? I'm using static
because if don't, when I do this call after the initialization:

run_function_menu(&my_function_menu);

I get a whole bunch of nothing

Hmm... are you using lcc-win32? This program:

#include <stdio.h>
#include <stdlib.h>

typedef struct function_item {
const char *descrip;
void(*function)(void);
} t_function_item;

typedef struct function_menu {
unsigned short num_items;
unsigned short default_item;
const char *title_prompt;
t_function_item *function_items;
} t_function_menu;

void my_function_1(void)
{
printf("in %s()\n", __func__);
}

void my_function_2(void)
{
printf("in %s()\n", __func__);
}

void run_function_menu(t_function_menu *function_menu, int item)
{
if (item < 0 || item >= function_menu->num_items)
item = function_menu->default_item;
printf("Do #%d %s: ", item, function_menu->function_items[item].descrip);
function_menu->function_items[item].function();
}

int main(int argc, char **argv)
{
t_function_menu my_function_menu = {
2, 0, "My Function Menu",
(t_function_item[]){
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}
}
};
run_function_menu(&my_function_menu, argc > 1 ? atoi(argv[1]) : 0);
return 0;
}

runs fine using gcc but gives a segmentation fault using lcc-win32.

Well, no, that's not the compiler I'm using, and per my original
question (now answered) I couldn't do the initialization in the first
place without getting syntax errors.

What I was talking about apparently was a figment of my
imagination...sort of. I thought this wouldn't work because
my_function_menu has to be declared as static in order to be
passed as a pointer in run_function menu():

void select_function(void) {
unsigned short menu_choice;
t_function_menu my_function_menu=
{0,0,"My Function Menu"};
t_function_item my_function_items[]={
{"My Function 1",my_function_1},
{"My Function 2",my_function_2},
{NULL,NULL}};
my_function_menu.function_items=my_function_items;

if((menu_choice=run_function_menu(&my_function_menu))!=0)
my_function_items[menu_choice-1].function();
}

Except I just tried it now and it works fine (as I would have thought
in the first place).

But this is "illegal initialization":

t_function_item my_function_items[] = {
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}};
t_function_menu my_function_menu = {
(sizeof my_function_items/sizeof my_function_items[0])-1, 0,
"My Function Menu",my_function_items};

But can be fixed by declaring only my_function_items as
static:

static t_function_item my_function_items[] = {
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}};
t_function_menu my_function_menu = {
(sizeof my_function_items/sizeof my_function_items[0])-1, 0,
"My Function Menu",my_function_items};

So is this all completely correct behavior under "C89", which
is apparently the controlling "standard" for this type of stuff for me?
Yeah, for a local initialization I guess I can't do that with this
compiler...

It looks like a general bug in the way structs get initialised to me.
Take this, for example:

#include <stdio.h>

int main(void)
{
int array[] = { 1, 2, 3 };
struct s {
int n;
int *items;
} s = { 3, array };
printf("%p %p\n", (void *)array, (void *)s.items);
return 0;
}

s.items does not get initialised.

For me, for what it's worth, it is just another "illegal initialization".
Again, adding static to the array[] declaration makes it work fine;
s.items is definitely initialized to the same value as array[]
and I can access the values in the array...
 
B

Ben Bacarisse

Bill Reid said:
Well, no, that's not the compiler I'm using, and per my original
question (now answered) I couldn't do the initialization in the first
place without getting syntax errors.

It was just a guess.

But this is "illegal initialization":

t_function_item my_function_items[] = {
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}};
t_function_menu my_function_menu = {
(sizeof my_function_items/sizeof my_function_items[0])-1, 0,
"My Function Menu",my_function_items};

Yes, in C90 all initialisers must be "compile-time constants" so a
pointer to an automatic variable is not allowed.
But can be fixed by declaring only my_function_items as
static:

static t_function_item my_function_items[] = {
{"My Function 1", my_function_1},
{"My Function 2", my_function_2},
{NULL, NULL}};
t_function_menu my_function_menu = {
(sizeof my_function_items/sizeof my_function_items[0])-1, 0,
"My Function Menu",my_function_items};

So is this all completely correct behavior under "C89", which
is apparently the controlling "standard" for this type of stuff for
me?

Yes, that is all standard and correct. If you are tied to C90 (=C89)
then it also explains your initial syntax errors. You originally
posted code that contained a compound literal (a C99 feature) and your
compiler would very likely reject it. That's why I went off on the
C99 tangent -- I thought is was available to you.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top