TinyURL widget - shorten your URL's for free!

Enter a long URL to make tiny:

Monday, April 11, 2016

Creating and using a .this pointer in C language structs



This blog post contains examples of how to create a this pointer in C. You may know "this.xxxx" is a C++ attribute of objects. Well like many things you can emulate it in C because C is far more flexible without the bloating that object oriented languages provide for lazy programmers to make mistakes.

Of course, in order to emulate in C it requires more knowledge/experience than the average starting programmer can do. And as websites develop bit rot for older technology these things get lost unless others decide to pick up the challenge to maintain them.  I do not claim to be the first to do this, I am sure it's been done, but I am the one making a clear explanation and re-introducing it as it were.

I tried to post to stack exchange but I do not meet the process nazi's interpretation of a good question so I won't bother providing them my help. I would rather be helpful than process-correct and I don't get paid to educate so I stick to the facts without superfluity in a non-educational idiom.

<\whining>

One can make a resident pointer to a struct of the same type like so:


You don't need the first cca_t I just use it to make my understanding easier.

Before a struct has been defined one can't refer to it. Some sort of causal loop error in programming form.  But one can declare it as a struct while defining the struct- itself?!? Another metaphysical argument I don't need to go into. I know this will work on GCC with default warnings and error flags and that's all I care about. I cannot confirm if it works with C-XXXX standard in general terms. CAVEAT EMPTOR. If you do find out it works I would appreciate 40 ms of your time to respond back below and we can leave all the comments in one spot for people to find them. Like me in 6 months when I return.

So the "this" pointer is a pointer without an array. Notice I include a pointer to a pointer to  the same struct being defined. In this case I am making a same-typed pointer (to pointer) that will be the receptor of similar pointers from neighbouring cells. I was making a cellular automata at the time so that was the context. I wanted to be able to define modular units that might end up on different threads in this version. So they can access in the same program frame addressing but not necessarily the same operation unit / lightweight process.

So far so good. Now, when you initialize / construct the dynamic struct with malloc:




You point the this at the pointer you will return at the end of the function.

In this instantiation, I make cell surfaces dependent on the same neighbour number to 0 cell means neighbour 0 and also state[0] for any values passed back and forth. Now I can iterate once and get it all.  I don't make a set pattern for cell walls because they might have arbitrary connectedness.

Now when I want to assign a neighbour to a cell it works something like this:




I assign b's b->this variable to the neighbour slot open in a's neighbour list.
And likewise assign a's this to b. I also assign the cell walls (neighbour connection) using the ADDRESS OF of the pointer not the VALUE of the pointer. Since the neighbour is inside the larger struct passed and we are using  a pointer -> pointer -> struct we are accessing the value by default when we aim at the second struct within a struct that was passed inside a function variable declaration because these are nested structs within structs.  I know that sounds like double talk but I am unrolling the order of operations and presenting it in a way that when you look at other explanations will make sense.

Pointers take time to understand and remember that pointers give a value or an address, not an array, when accessed. That's why a pointer to element with offset indexing leads to another pointed-to element. An array is guaranteed for your program's sake (as far as it can see) to be a contiguous length of memory of type.

The struct is a value when accessed one way, it is an address when accessed the other.

I don't like the *( a + i).element method of writing C structs because it is a babyish technique taught by naive professors that have never dared to make more complicated nested code. Some claim it is faster and I don't dispute that but I doubt they've tried harder because they stop teaching at the semester end. Probably because when you present the same material every year no one challenges you to prove you can do more. It makes sense for basic applications which is what they can show you. But working code lives and gets more complex. Programmers don't.

I claim it's babyish because I dare them to keep this kind of nested logic straight in their mind when writing it.

*((((a+i)+j)+k)+l)+m).element

So

&(b->state[b->neighbour_number]).st

gives us the address of the pointed to state address (.st) inside the nested pointers and this can continue with a rational understanding of the content within like so:

&(b->state[b->neighbour_number]->neuron[b->cell_number]->synapse[b->geo_number]).st

ad infinitum with a rational way to understand what was written. I can make iterator names that make sense and I can understand 10 files all at once. All the element indices can be maintained at the top level and iterated which is really the operation that most code undergoes. But what is different here is people can make a direct understanding of the things operating on things because that is the level humans work at. That is what costs the most time; understanding what code does not writing perfect code. Machines are better in most cases for optimization except for ATLAS as far as I know. R. Clint Whaley is an uber nerd and he writes sparse matrix optimizations by hand.

I follow the unix philosophy  writing understandable code and leaving optimization as another step:

"Worse is better"

I work in research so I don't worry about development as much as making sure it works. But with a top level iteration mechanism the GCC compiler can then unroll for loops for speed or optimize for memory. But the human being writes code and then goes off for 3 months and then has to come back to it.

This is why writing things like a .this pointer make it easier to grasp what you wrote and then evolve it quickly with patterns that make sense.







9 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. I don't like OO, so I'm going to put the one feature of OO into C that makes OO possible.

    *blink*

    ReplyDelete
    Replies
    1. Worse yet.... I'll do it in a language that doesn't guarantee it.

      Someone can come along and put a car in your cat's this pointer...

      And now you've totally destroyed strong-typing.

      Delete
  3. I can't tell if this post is a joke or plain stupidity.

    ReplyDelete
  4. What is even the point of doing it? The "this" pointer in C++ is free, it doesn't cost a field on every object. It's available when you call a method on an object, so that you know the objects own address if necessary. It's rarely even used in code. Since C doesn't have methods, it's all functions all the time, you already know the address of every element in your function. What purpose would a this pointer serve?

    ReplyDelete
  5. http://philosophical-ranting.blogspot.com/2016/04/splash-and-dash-applying-lonely.html

    ReplyDelete
  6. Nice, so basically, you can have a pointer ta a struct if you already have a pointer or a reference to it. So useful...

    ReplyDelete
  7. typedef struct cca_t cca_t;

    struct cca_t {
    ...
    cca_t this;
    ...
    };

    ReplyDelete
  8. typedef struct cca_t cca_t;

    struct cca_t {
    ...
    cca_t this;
    ...
    };

    ReplyDelete