NO

Author Topic: When are structs initialized  (Read 7182 times)

siwenjo

  • Guest
When are structs initialized
« on: December 31, 2013, 07:07:24 PM »
If I declare a struct in main like:

Code: [Select]
struct Car mycar;
then memory is made available for the Car struct. But what happens if I send out a struct as a void pointer parameter, for example:

Code: [Select]
void *myCar = new(Car, model);
to be accepted by the function:

Code: [Select]
void *new(const void *_class, ...){...}
As a parameter has a Car struct been initialized or what is its status? I am trying to understand Axel-Tobias Schreiner's ooc.






Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: When are structs initialized
« Reply #1 on: January 01, 2014, 06:42:13 PM »
PellesC is a 'C' compiler not a C++ compiler. It doesn't support classes nor the 'new' operator.
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

siwenjo

  • Guest
Re: When are structs initialized
« Reply #2 on: January 02, 2014, 09:47:11 PM »
This is no sort of an answer. Schreiner's work is a viable (compilable) way of using C, and there, new is simply a global function. What I asked is whether a void pointer when passed as a parameter initialized the struct it pointed to; not whether C was OOP.

Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: When are structs initialized
« Reply #3 on: January 02, 2014, 09:58:42 PM »
This is no sort of an answer. Schreiner's work is a viable (compilable) way of using C, and there, new is simply a global function. What I asked is whether a void pointer when passed as a parameter initialized the struct it pointed to; not whether C was OOP.
It is always a bad idea of relying on a specific compiler behavior instead to properly initialize variables yourself, OOP or not OOP, C or C++ (or whatever programming language/compiler strikes your fancy).

Ralf

siwenjo

  • Guest
Re: When are structs initialized
« Reply #4 on: January 03, 2014, 02:02:37 AM »
Please, I am not asking a political question but a question about C. What is the status of the void pointer handed off to new as a parameter?

Code: [Select]
void *myCar = new(Car, model);
...
void *new(const void *_class, ...){
  const struct Class* class = _class;
  ...
}

As a void pointer I would assume it was a declared pointer pointing to whatever rubbish the address space it occupied contained. But then what is the purpose of handing it a Car struct. Or does the actual passing of the name of the struct type (Car) actually generate a Car object/structure in memory and point the void pointer to it?

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: When are structs initialized
« Reply #5 on: January 03, 2014, 03:46:20 PM »
Please, I am not asking a political question but a question about C.
And ours are *not* political answers  ::)
The way you asked the question have some sense when looking from an OOP point of view, but in reference to standard 'C' have no sense.

What is the status of the void pointer handed off to new as a parameter?

Code: [Select]
void *myCar = new(Car, model);
...
void *new(const void *_class, ...){
  const struct Class* class = _class;
  ...
}
You are *not* passing a void pointer as parameter, but rather assigning to a void pointer the result of your function.
Moreover your function is declared as returning a pointer to void.
If your question is 'what is a void pointer type?' then we should better address you to review the basics of C/C++.
Anyway a void pointer is a variable that can hold the value of any type of pointer. You can assign to it pointers of int, float, double, structures, etc.
What you assign to it is assumed to be usefull to your program.

As a void pointer I would assume it was a declared pointer pointing to whatever rubbish the address space it occupied contained. But then what is the purpose of handing it a Car struct. Or does the actual passing of the name of the struct type (Car) actually generate a Car object/structure in memory and point the void pointer to it?
From basics to advanced usage  ;D
When programmers want to pass something without specifyng it's real nature generally pass a point to the describing structure hooded under a 'void pointer' type.
I.e. this is what Windows does passing handles, if look deep in win headers you'll see that 'HANDLE' is defined as 'LPVOID' alias 'void *'. The same assignement is shared with all specialized handles like 'HWND', 'HBITMAP', 'HOBJ', etc.
What is the benefit of this?  ::)
To pass different types of variables with the same declaration and to 'obscure' the real contents of the struct or variable. This on one side mimics the OOP languages objects handling, and on the other side protects private data from user.
In your specific case giving to the user only a void pointer you don't allow to user any access to Car structure internals protecting it from bad handling. The user only knows that he has to create a 'Car' object calling 'new' function, thet returns an handle to the new object (a void pointer!  :o ).
Then you can use the object by means of function provided that works on that object.

Windows calls analyze the passed handles to discover which object they describe then calls the appropriate function to handle specific objects.

Look my sample here...

Enough?  ;D
« Last Edit: January 03, 2014, 04:13:22 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: When are structs initialized
« Reply #6 on: January 03, 2014, 09:10:20 PM »
Frankie pretty much summed this all up.

My reply was certainly not "political" (in terms of C vs. C++) but I tried to make clear that the state of the variables is simply undetermined unless you explicitly initialize them before passing.

And as Frankie also already pointed out "void" pointers are simply that, pointers to a region of memory that can contain any kind of value, initialized or not.

Ralf

siwenjo

  • Guest
Re: When are structs initialized
« Reply #7 on: January 03, 2014, 11:06:21 PM »
Thank you for your replies but I think we are still talking at crossed purposes. I found another example that better illustrates the confusion I am having, a hash map storing void pointers to pointers:

Code: [Select]
typedef struct {
    int size;
    void **keys;
    void **values;
} Hash;

has keys and values inserted into it:

Code: [Select]
void hash_insert (Hash *hash, void *key, void *value) {
    int index = hash_index(hash, key);
    hash->keys[index] = key;
    hash->values[index] = value;
}


by passing these keys and values as parameters:

Code: [Select]
hash_insert(hash, "hello", "world");

My confusion is that the hash struct only keeps void pointers to pointers which in this case means pointers to the void pointers passed into hash_insert as "hello" and "world". As such **keys and **values indirectly point to the address that contains the strings stated in the calling statement (the last piece of code). But these strings are real objects that occupy memory and therefore have an address. If, like the Car example I were to pass the type of the parameters rather than instances of the type:

Code: [Select]
hash_insert(hash, char*, char*);
for example, then I do not understand what it is that **keys and **values would be pointing to because the char* statement does not grab any memory and therefore has no address for the pointers to point to. If it was simply a cast then why does the compiler not complain when, in the example from the previous posts, the void* cast as Car gets assigned to the Class struct?

As an observation, and I think I am right in this, this implementation of a hash map would be terrible because as soon as the calling statement went out of scope the memory occupied by "hello" and "world" would be reclaimed and possibly overwritten and so **keys and **values would come to point to some trash they should not have access to.

Maybe the questions are advanced but I have not programmed C for years and that I did only briefly so I don't consider myself comfortable or familiar with it.

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: When are structs initialized
« Reply #8 on: January 04, 2014, 10:41:50 PM »
Dear Siwenjo,
what you ask is related to basic knowledge of C programming. May be this and this can help.
In the specific case of hashing consider that the scope of the author was to create such a function to hash store whatever type of variable and key. For this reason the best solution is to create a struct with variables capable to hold any type o values. In the specific it keeps the address of any type of variables.

Try:
Code: [Select]
int        i = 1;
float     f = 1.0
double d = 2.0;
char     binary[]="\x01\02\x3";
struct
{
    int a;
    float b;
} MyStruct;

hash_insert(hash, "hello", "world");
hash_insert(hash, "int", &i);
hash_insert(hash, "float", &f);
hash_insert(hash, "double", &d);
hash_insert(hash, "struct", &MyStruct);

You will see that it works!  :o

The declaration:

Code: [Select]
void **ptr;

Defines a variable that can hold a pointer to whichever type of variable, in other words this varible can store the address of any kind of data.
The advantage of using a pointer is that its size is the same for any kind of data, and allowe to write this simple declaration:

Code: [Select]
typedef struct {
    int size;
    void **keys;
    void **values;
} Hash;

Without using the pointers you sould have used something like:

Code: [Select]
typedef struct {
    int size;
    void **keys;
    union
   {
       int  int_val;
       float  f_val;
       double d_val;
       char  c_val;
       char  *s_val;
       ...                     //All the existent types....
   };
} Hash;

But 'MyStruct' whould have not fit unless you modified the 'Hash' typedef for each new structure or union you could create  ::).

"hello" and "world" are string constants (and are stored in read only section of executable file) and exist forever. Yes you cannot retrieve the addresses of these strings outside their definition point, but you passed their address to be stored in hash structure from where you can get them back in any moment  8).

I wouldn't be rude, but if you don't review your understanding of void and void pointer types you would never go beyond  ;)
« Last Edit: January 04, 2014, 10:51:20 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: When are structs initialized
« Reply #9 on: January 05, 2014, 05:59:40 AM »
Thank you for your replies but I think we are still talking at crossed purposes. I found another example that better illustrates the confusion I am having, a hash map storing void pointers to pointers:

Code: [Select]
typedef struct {
    int size;
    void **keys;
    void **values;
} Hash;
You need to be aware that this is a "typedef" only, it only defines the layout of the type. This is not a variable with specifically allocated memory space!
Quote
has keys and values inserted into it:

Code: [Select]
void hash_insert (Hash *hash, void *key, void *value) {
    int index = hash_index(hash, key);
    hash->keys[index] = key;
    hash->values[index] = value;
}


by passing these keys and values as parameters:

Code: [Select]
hash_insert(hash, "hello", "world");
And this will only work (properly) is the variable from type "Hash" named "hash" at some point has been defined. A function parameter does this only as far as passing this parameter is concerned!
Quote
My confusion is that the hash struct only keeps void pointers to pointers which in this case means pointers to the void pointers passed into hash_insert as "hello" and "world". As such **keys and **values indirectly point to the address that contains the strings stated in the calling statement (the last piece of code). But these strings are real objects that occupy memory and therefore have an address. If, like the Car example I were to pass the type of the parameters rather than instances of the type:

Code: [Select]
hash_insert(hash, char*, char*);
for example, then I do not understand what it is that **keys and **values would be pointing to because the char* statement does not grab any memory and therefore has no address for the pointers to point to. If it was simply a cast then why does the compiler not complain when, in the example from the previous posts, the void* cast as Car gets assigned to the Class struct?
Again, for your example to work, the variable named "hash" (from type "hash") needs to be defined before it can be used for this. Just having this as a function parameter called "hash" will not do this.
This is general C (and not much different from C++ in that regard).
Quote
As an observation, and I think I am right in this, this implementation of a hash map would be terrible because as soon as the calling statement went out of scope the memory occupied by "hello" and "world" would be reclaimed and possibly overwritten and so **keys and **values would come to point to some trash they should not have access to.
Not "terrible" because your example is incomplete. You missing the part where you are allocating the space for your hash table (elements).
The function hash_insert() will just perform the operation with the parameters you apply to it. And if those memory areas that those parameters you are referring to when passing (by using void pointer or any other means, this is the same basic problem), the function will happily overwrite the memory areas those pointers are arbitrarily pointing to.
Quote
Maybe the questions are advanced but I have not programmed C for years and that I did only briefly so I don't consider myself comfortable or familiar with it.
As Frankie pointed out, without anything personal, your basic problem is basic comprehension of basic C functionality...

Ralf

siwenjo

  • Guest
Re: When are structs initialized
« Reply #10 on: January 05, 2014, 02:56:08 PM »
So you don't know!

Offline Stefan Pendl

  • Global Moderator
  • Member
  • *****
  • Posts: 582
    • Homepage
Re: When are structs initialized
« Reply #11 on: January 05, 2014, 03:42:52 PM »
So you don't know!

In general, variables and structures are never initialized for you in C automatically.
This is by design of the C language.

Many compilers allow initializing a structure to all zeros by setting it equal to {0}.
There are functions provided by the operating system to zero memory too.
---
Stefan

Proud member of the UltraDefrag Development Team

Offline frankie

  • Global Moderator
  • Member
  • *****
  • Posts: 2113
Re: When are structs initialized
« Reply #12 on: January 05, 2014, 07:00:52 PM »
So you don't know!
Maybe!  ;D If this is what you understood from our answers...
But are you confident to be aware of what you are talking about?!?!?  ;D
« Last Edit: January 05, 2014, 10:20:38 PM by frankie »
"It is better to be hated for what you are than to be loved for what you are not." - Andre Gide

siwenjo

  • Guest
Re: When are structs initialized
« Reply #13 on: January 06, 2014, 02:05:00 AM »
The problem was that the Stringsent as parameter to the void pointer was actually declared and initialized in the String files and I had not realized that they were globals; String is used both as the name of the struct and the name for a global void pointer to an initialized String struct. The full code is Schreiner's and can be found at http://www.cs.rit.edu/~ats/books/ooc.pdf

Anyway I have simplified the code just to show what was going on:

Code: [Select]
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>


//const void* House;
void* new(const void* class);

struct Class{
size_t size;
void* (*ctor) (void* self, char* address);
};

struct House{
const void* class;
char* address;
};

void* House_ctor(void* _self, char* address);

const struct Class _House = {
sizeof(struct House), House_ctor
};
const void* House = &_House;

int main(void){
void* house = new(House);

struct House tmp = *(struct House*)house;
printf("Address is from main: %s\n", tmp.address);
}

void* new(const void* _class){
const struct Class* class = _class;
void* p = calloc(1, class->size);
assert(p);
*(const struct Class**)p = class;

if(class->ctor){
p = class->ctor(p, "An address");
}

char* tmp = (*(struct House*)p).address;
printf("Address is from new: %s\n", tmp);

return p;
}

void* House_ctor(void* _self, char* address){
struct House* self = _self;
const char* text = address;

self->address = malloc(strlen(text) + 1);
assert(self->address);
strcpy(self->address, text);

printf("Address is from House_ctor: %s\n", self->address);

return self;
}



Offline Bitbeisser

  • Global Moderator
  • Member
  • *****
  • Posts: 772
Re: When are structs initialized
« Reply #14 on: January 06, 2014, 05:24:03 AM »
The problem was that the Stringsent as parameter to the void pointer was actually declared and initialized in the String files and I had not realized that they were globals; String is used both as the name of the struct and the name for a global void pointer to an initialized String struct. The full code is Schreiner's and can be found at http://www.cs.rit.edu/~ats/books/ooc.pdf

Anyway I have simplified the code just to show what was going on:
Well, not sure what "string" you are now talking about, but the key to the whole thing in your code you posted is this line
Code: [Select]
void* p = calloc(1, class->size);in the new() function. calloc() is for one allocating a chunk of memory and in contrast to the more common malloc(), is specifically "zero-initializing" this chunk of memory. This is what was in all of your previous posts missing and I tried to make you aware of, that you specifically have to initialize a variable yourself if you depend on this variable to have a specific value/state....

Ralf