Let me offer you my beginner explanation on this kind of situation and let us see where exactly come this one first.
Sit back and relax because it is going to be messy.
C language
A beginner naive decision we find it all the time and in all possible situations as well.
Let us take a look at the following C example:
char *ptr = NULL;
ptr = malloc( 256 * sizeof( *ptr ) );
The new comers see this two lines like the following:
- declaring ptr as a pointer to char and set it to NULL.
- allocating memory for the Pointer.
Now you see, here is a big problem of understanding the things what exactly happens.
You never allocate memory for the pointer, what exactly really happens is:
- you are making a request to the Operating System.
- this request takes place with the help ( by calling) of the malloc() function.
- again, this request takes place only and I repeat ONLY, if your Compiler is involved as well.
- you can (probably) get this memory (if there is some free memory of course) only if it could be reserved some of it for your application.
Now this is an example of a long chain of things what really happens when you are trying to get some memory for your application.
Lets us move on:
char *ptr = NULL;
ptr = "A string";
Another beginner naive understanding would be:
- declaring ptr as a pointer to char and set it to NULL.
- create a String called “A string”.
You see here are also a lot of misunderstanding things:
- declaring ptr as a pointer to char and set it to NULL.
- You never create a String, in fact in C, there are NO strings at all.
- “A string” it is a Literal String, which means that it is created in a spacial place ( Read Only Memory) inside memory and it is very hard coded as well.
- you cannot (and you should never try) ever modify a Literal string.
- in other words this: “A string”, it is a null terminated sequence of characters.
- that being said, here “ptr = “A string”;” you are pointing your pointer to that location where only Read can take place.
Now lets us see the next example:
char arr[256] = "A string";
Here a naive beginner would say:
- we declare an array and we create a string.
Well this is not a bad explanation, because at some point you are doing that, but what’s the story with it?
Wel, let us split them to see what exactly happens:
- char arr[256] means that you are requesting a memory enough (up to) 256 bytes for your char.
- = “A string”; means that you are initializing a part of that requested memory with that information.
Now the thing are a little bit different, why?
-
you make a request of 256 bytes.
-
you are creating a Literal String, which again is hard coded in Read-Only-Memory
-
at a moment when you are initializing your char, what really happens is that you are making a copy of that Literal String ( “A string” ) and you put that value (the copy) inside your char.
-
again, what you are later doing with your array, has nothing to do with the Literal String “A string”.
-
if fact the value of your array, which is “A string” has nothing to do with the Literal String “A string” which you set it up at the moment when you initialized your Array.
-
if you think that there is exactly the same value, then a naive beginner would thing that this should be correct:
char arr[256];
arr = "A string";
Now because we understand the basics lets move on to the real problem.
When you are declaring a pointer which gets initialized with a value, more over when you pointer points to a valid memory location at the moment of its declaration ( where becomes a definition as well), like this:
char *arr = "A string";
You got your self to problems, but why?
Again, go up some lines an read about what a Literal String is.
- “A string” is only a valid memory location for you application with respect to its read-only-memory location.
- it is not something what you as User or through your application to play with.
This bring us to this:
const char *ptr = "A string";
This is the only valid declaration and initialization (which is also a definition) in C.
Why this is this the Right way?
- by putting that const qualifier in front of char* we are informing our Compiler that we are going to work with some read-only-memory location
- this mean you do a promise to your compiler that you are not going to “play” with that memory at all, and you are only going to use that value at some point in your application.
Now knowing that give us now to opportunities to work with that Literal string:
1)
char *arr = "A string";
arr[0] = 'B';
Here you get your self with a nice Segmentation fault.
const char *arr = "A string";
arr[0] = 'B';
Here you get your self with a warning that you are trying to mess your Read-Only-Memory location, of course only if you are using a proper compiler (like GCC for example).
Why a warning instead of a Segmentation fault? Well because that const qualifier it is like a “cast” for your compiler, but depends if which level of understanding you are using the word “cast” in situations like this one here were the const qualifier is involved.
Now it is the GTK’s time.
There is a difference between using plain C cast: (type*)
or doing a TYPE_CASTING() in GCC.
- the first one is only a plain cast in C.
- the second one is not a cast at all, it is a MACRO used to check for compatibility of two types.
- this MACRO does a Run-Time-Check four you.
Now let us see this example:
#include <gtk/gtk.h>
int main ( int argc, char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
gtk_init ( &argc, &argv );
/// *** Create a Window
window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
gtk_window_set_default_size ( GTK_WINDOW ( window ), 200, 200 );
/// *** create a button
button = gtk_button_new_with_label ( "Click me" );
gtk_container_add ( GTK_CONTAINER ( window ), button );
/// *** example 1
gtk_window_set_title ( GTK_WINDOW ( window ), "my Window" );
/// *** example 2
gtk_window_set_title ( ( GtkWindow* ) window, "my Window" );
/// *** Show them all and loop
gtk_widget_show_all ( window );
gtk_main();
}
There is no fundamental difference for you to choose example 1 or example 2, because you are passing the right pointer.
How about this?:
#include <gtk/gtk.h>
int main ( int argc, char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
gtk_init ( &argc, &argv );
/// *** Create a Window
window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
gtk_window_set_default_size ( GTK_WINDOW ( window ), 200, 200 );
/// *** create a button
button = gtk_button_new_with_label ( "Click me" );
gtk_container_add ( GTK_CONTAINER ( window ), button );
/// *** example 1
gtk_window_set_title ( GTK_WINDOW ( button ), "my Window" );
/// *** example 2
gtk_window_set_title ( ( GtkWindow* ) button, "my Window" );
/// *** Show them all and loop
gtk_widget_show_all ( window );
gtk_main();
}
in the example 1 case where the MACRO is used:
gtk_window_set_title ( GTK_WINDOW ( button ), "my Window" );
You get a nice warning:
(Scale:4359): GLib-GObject-WARNING **: 11:11:09.907: invalid cast from ‘GtkButton’ to ‘GtkWindow’
(Scale:4359): Gtk-CRITICAL **: 11:11:09.907: gtk_window_set_title: assertion ‘GTK_IS_WINDOW (window)’ failed
In case of the example 2 where a plain C cast is used:
`gtk_window_set_title ( ( GtkWindow* ) button, "my Window" );`
You get a complicate short warning (happy debugging:
(Scale:4411): Gtk-CRITICAL **: 11:14:05.426: gtk_window_set_title: assertion ‘GTK_IS_WINDOW (window)’ failed
Now why would you think that the use of cast is not (or should not be) needed and some one should reinvent a system which already exists just to conform to your need?
Let me show you 95% of mistakes in simple applications:
The wrong GTK Code:
#include <gtk/gtk.h>
void clicked_callback ( GtkWidget *button, gpointer data );
int main ( int argc, char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
gtk_init ( &argc, &argv );
/// *** Create a Window
window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
gtk_window_set_default_size ( GTK_WINDOW ( window ), 200, 200 );
/// *** create a button
button = gtk_button_new_with_label ( "Click me" );
/// g_signal_connect_swapped() is the right call here
g_signal_connect( button, "clicked", G_CALLBACK( clicked_callback ), NULL );
gtk_container_add ( GTK_CONTAINER ( window ), button );
/// ***
gtk_widget_show_all ( window );
gtk_main();
}
void clicked_callback ( GtkWidget *button, gpointer data )
{
/// 1) What is the Story with GtkWidget instead of GtkButton?
/// 2) What is the Story with gpointer data?
g_print ( "The button was pressed\n" );
}
The right GTK Code:
#include <gtk/gtk.h>
void clicked_callback ( GtkButton *button );
int main ( int argc, char *argv[] )
{
GtkWidget *window;
GtkWidget *button;
gtk_init ( &argc, &argv );
/// *** Create a Window
window = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
gtk_window_set_default_size ( GTK_WINDOW ( window ), 200, 200 );
/// *** create a button
button = gtk_button_new_with_label ( "Click me" );
g_signal_connect_swapped( button, "clicked", G_CALLBACK( clicked_callback ), button );
gtk_container_add ( GTK_CONTAINER ( window ), button );
/// ***
gtk_widget_show_all ( window );
gtk_main();
}
void clicked_callback ( GtkButton *button )
{
if ( GTK_IS_BUTTON ( button ) )
{
g_print ( "The button was pressed\n" );
}
}
Answer: in the case of the first code, should never be used.
I hope you understand the differences now.
Please join my YouTube channel for more information about working with GTK3, CSS and C language ==>> https://www.youtube.com/channel/UCeZXCNsTodx0EPcAfc6s0Ew/playlists
Have a nice Day.