0

I want to create a multiple array of my structure:

#include <gtk/gtk.h>
#include <glib/gi18n.h>

typedef struct  {
    gchar icon_name[24];
    int response;
    gchar label[10];
} button_data;

GtkWidget * create_button_helper (GtkDialog *dialog) {
    button_data b[3] = {
        { "dialog-ok", GTK_RESPONSE_YES, _("Yes")},
        { "dialog-close", GTK_RESPONSE_NO, _("No") },
        { "", 0 }
    };
    gint index;
    for (index = 0; b[index].response != 0; index++) {
        GtkWidget *tmp;
        GtkWidget *i;
        tmp = gtk_button_new_with_label (b[index].label);
        i = gtk_image_new_from_icon_name (b[index].icon_name, GTK_ICON_SIZE_BUTTON);
        gtk_button_set_image (GTK_BUTTON (tmp), i);
        gtk_dialog_add_action_widget (GTK_DIALOG (dialog), tmp, b[index].response);
    }
}

But I get the error about invalid initializer, any helps?

When compiled with gcc -Wall the following relevant warnings are given:

./tmp.c: In function ‘create_button_helper’:
./tmp.c:12:9: warning: missing braces around initializer [-Wmissing-braces]
         { "dialog-ok", GTK_RESPONSE_YES, _("Yes")},
         ^
./tmp.c:12:9: warning: (near initialization for ‘b[0].label’) [-Wmissing-braces]
./tmp.c:12:9: warning: initialization makes integer from pointer without a cast [enabled by default]
./tmp.c:12:9: warning: (near initialization for ‘b[0].label[0]’) [enabled by default]
./tmp.c:13:9: warning: initialization makes integer from pointer without a cast [enabled by default]
         { "dialog-close", GTK_RESPONSE_NO, _("No") },
         ^
./tmp.c:13:9: warning: (near initialization for ‘b[1].label[0]’) [enabled by default]
user12205
  • 2,684
  • 1
  • 20
  • 40
Joel
  • 1,805
  • 1
  • 22
  • 22

3 Answers3

2

Just change the struct definition to

typedef struct  {
    const gchar *icon_name;
    int response;
    const gchar *label;
} button_data;

be aware that the values of icon_name and label will not exists outside of the create_button_helper, but it seems you wont need them anywhere else.

Also initialize the array this way

button_data b[3] = {
    { "dialog-ok", GTK_RESPONSE_YES, _("Yes")  },
    { "dialog-close", GTK_RESPONSE_NO, _("No") },
    { NULL, 0, NULL }
};

and in the loop you can use

for (index = 0; b[index].icon_name != NULL; index++)

also, if you have a sentinel value you don't need to specify the size of the array (as the constructive comments from @chux mention add the const here) this would be better in fact

const button_data b[] = {
    { "dialog-ok", GTK_RESPONSE_YES, _("Yes")  },
    { "dialog-close", GTK_RESPONSE_NO, _("No") },
    { NULL, 0, NULL }
};

since now you can add more button_datas to your array, wihtout changing anything else.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • 1
    Why the 2nd `const` in `const gchar *const icon_name;`? Should not `const gchar *icon_name;` be sufficient? – chux - Reinstate Monica Dec 29 '14 at 18:04
  • It would be, however it is a good practice to mark everything `const` which is not meant to be changed. For reference: http://stackoverflow.com/questions/1446120/const-usage-with-pointers-in-c – meskobalazs Dec 29 '14 at 18:10
  • 2
    Minor: Reassigning the pointer `const gchar *icon_name` would not be a problem. @meskobalazs If the `button_data` was meant to be `const`, code should be `const button_data b[3] = ...`. – chux - Reinstate Monica Dec 29 '14 at 18:15
  • Nice use of sentinel. – chux - Reinstate Monica Dec 29 '14 at 18:25
  • `"dialog-ok"` is a `const char *`. Does that convert directly to `const gchar *`? Or does code need `_("dialog-ok")`? – chux - Reinstate Monica Dec 29 '14 at 18:36
  • Thanks iharob, your explanation helped... kudos for you ^_^ – Joel Dec 29 '14 at 18:40
  • @chux No, `gchar` is just `typedef char gchar;` and `_(x)` macro expands to `gettext(x)` a gnu function for string translation. – Iharob Al Asimi Dec 29 '14 at 19:02
  • Minor point: Curious about `typedef char gchar`. If that is _always_ true, why have a typedef and instead just use `char`? Suppose that is an SO question. If is not always true, then this solution may have a problem with `typedef something_else gchar`. – chux - Reinstate Monica Dec 29 '14 at 19:12
  • 1
    @chux You are right, and may be it's not true for other operating systems, but I can't be sure, because have I never worked on a cross platform `gtk+` app. It could actually be a SO question it think. I use Linux by the way, so by others a actually suspect of MS Windows, since they have a `TCHAR` which could be `char` or `wchar_t` so I suppose there it could be `typedef TCHAR gchar`. Although the fix would be to use the `TEXT()` macro, and one can perfeclty write one for compatibility like `#define TEXT(x) (x)`. – Iharob Al Asimi Dec 29 '14 at 19:22
1

I am not sure about the reason, but it seems that the minimal change to your code to make it work would be to change the type of the label of the struct to a pointer instead of an array:

gchar *label;

This may be because the _() macro expands to something that returns a gchar *, but again I'm not sure.


Update: Just checked glib's source code:

In glib/gi18n.h, we have (excerpt):

#include <libintl.h>
#include <string.h>

#define  _(String) gettext (String)

And in libintl.h we have (excerpt):

extern char *gettext (const char *__msgid)
     __THROW __attribute_format_arg__ (1);

So I guess this is why char[] doesn't work but char * does.

user12205
  • 2,684
  • 1
  • 20
  • 40
  • may be but don't post this as an answer, do it as a comment. And usually the `_(x)` macro expands to `gettext((x))` which returns `char *` so there should not be any problem with the `const` qualifier, the result of `gettext()` should not be modified in however, and it is actually a warning in it's manual page. – Iharob Al Asimi Dec 29 '14 at 18:09
  • 1
    @iharob I get your `const gchar *` part but I don't get why the pointer has to be constant - that part can be modified without causing any problems. – user12205 Dec 29 '14 at 18:16
0

this

button_data b[3] = {
        { "dialog-ok", GTK_RESPONSE_YES, _("Yes")},
        { "dialog-close", GTK_RESPONSE_NO, _("No") },
        { "", 0 }
};

is bad, the first two init lists are 3 elements and the last one is 2, also to be syntactically correct

button_data b[3] would be button_data b[][3].

Although I suspect this is not what you are trying to achieve, you will want something more like this.

button_data b[3] = {
    some_button_data, some_button_data, some_button_data
}

Because button_data probably can't be initialized the way you are trying to do it with an array initialization list.

But I'm not really used to GTK 3 so I can't help you beyond this.

tom
  • 354
  • 4
  • 15