Thread: On trickle down economics... I mean pointers.

  1. #1
    Registered User
    Join Date
    May 2016
    Posts
    104

    On trickle down economics... I mean pointers.

    Greetings folks,

    I have the following main:
    Code:
        t_dserver    display_server;
        t_scene        scene;
    
        if (argc == 2)
        {
            bzero(&display_server, sizeof(display_server));
            bzero(&scene, sizeof(scene));
            connect_display_server(&display_server);
            generate_scene(&scene, argv);
            render(&scene, &display_server);
            launch_event_manager(&display_server, &scene);
        }
        printf("Usage: program file_input\n");
        return (EXIT_SUCCESS);
    Whenever I find an error, or a normal quit condition, I call a shutdown() function -defined elsewhere- and clean everything, close handles, free memory, etc, before exiting.
    The problem is I'm having a hard time accessing the two structures, display_server and scene from within all sections of my code that handle exit conditions. Short of passing these two structures everywhere that I may need to call shutdown(), even though I don't have any other reason to use the structures in that specific section, or making the structures global I don't see a way around the issue.

    The latter choice is out of the question as I'm forbidden from using global variables. That leaves the first choice; problem with that is that I'm limited to using a max of four parameters per function. So even though I normally have pointers to the structures in the primary -read extern- functions of any given source file, I may not have enough parameter-budget left to pass the pointers to the satellite functions in that translation unit.

    I came up with a "hack", that seems to work very well. I store each structure pointer in a static variable inside an adequately named function, then use this function to gain access to the structure. e.g
    Code:
    t_dserver *get_display_server(t_dserver *serverptr)
    {
        static t_dserver *dserver;
    
        if (!dsever && serverptr)
            dserver = serverptr;
        return (dsever);
    }
    I would call this with a valid t_dserver argument once, to save the pointer, then use (void*)0 in subsequent calls when retrieving it.

    What do you guys think of this? Any pitfalls I'm not thinking of?
    Given the constraints I'm bound with, is there a better solution?


    Thanks.
    printf("I'm a %s.\n", strrev("Dren"));

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Why not remove the variable declaration within main altogether and go with
    Code:
    t_dserver *get_display_server()
    {
        static t_dserver dserver = { 0 }; // saves a bzero call
        return &dserver;
    }
    Then your first part of main is
    Code:
    if (argc == 2)
    {
        connect_display_server(get_display_server());
        /// etc
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2016
    Posts
    104
    YES, I like it!

    You know, deep down I felt there was something off with my solution, I just couldn't pinpoint it to anything specific. Guess that's what drove me here.
    Upon first look at your code, it just clicked. It's simple, elegant, efficient; the hallmark of good taste. I think Linus Torvalds would approve.

    printf("I'm a %s.\n", strrev("Dren"));

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Salem's suggestion is effectively a Meyer's singleton, if you want to do further reading.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    I have to say that your "hack" isn't very useful and it is dangerous. The local dserver pointer isn't initialized to NULL by default on automatic local variables. Essentially what you are trying to do is:
    Code:
    t_dserver *get_display_server( t_dserver *p )
    {
       // notice: Declared as static!
      static t_dserver *q = NULL;
    
      if ( !q ) 
        q = p;
    
      return q;
    }
    This is almost the same as declaring a global variable, but, instead of accessing the global variable directly, you are doing a function call and a comparison, in every access. If performance is important, this will not be good.

    But, of course, this is redundant (you are passing the pointer to the function here!).

    If you need to pass multiple arguments a single one I suggest you use a structure:
    Code:
    typedef struct {
      int a;
      void *p;
      float x, y, z;
      char *sptr;
    } args_T;
    
    void myfunc( args_T * );
    
    args_T args = { .a = 1, .p = &xpto, .x=1.0f, .sptr = str };
    myfunc(&args);
    This is essentially the same as passing multiple arguments directly, but you'll need to initialize the structure only once if you want to pass the same arguments to multiple functions and your structure could be dynamically allocated if you wish:
    Code:
    args_T *args = malloc( sizeof *args );
    *args = (args_T){ .a=1, .p=&xpto, .x=1.0f, .sptr = str; }
    myfunc(args);
    free(args);
    And you have an advantage: unused args will be automatically initialized to 0.
    Last edited by flp1969; 07-17-2019 at 03:39 AM.

  6. #6
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Ahhh... and Salem's tip for initializing structures (or arrays) is a very good one... This let the compiler to choose the better approach. For instance, on Intel processors, in x86-64 mode, this:
    Code:
    struct mystruct { int a, b, c, d; } s = {0};
    Could be compiled easily with two single instructions:
    Code:
    pxor xmm0,xmm0
    movups [s],xmm0
    x86-64 mode ALWAYS supports SSE, so this is safe assumption...

    if your processor supports AVX (and you compile for it), the block can be as big as 32 bytes long, the compiler would create code like this:
    Code:
    vpxor ymm0,ymm0,ymm0
    vmovups [s],ymm0
    Of course, if your code is compiled to AVX512, 64 bytes long (using zmm registers).
    Last edited by flp1969; 07-17-2019 at 03:47 AM.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by flp1969
    The local dserver pointer isn't initialized to NULL by default on automatic local variables.
    True, but dserver in post #1 is a static local variable, so it will be zero initialised at startup.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by laserlight View Post
    True, but dserver in post #1 is a static local variable, so it will be zero initialised at startup.
    Hummm... true... my bad...

  9. #9
    Registered User
    Join Date
    May 2016
    Posts
    104
    Interesting development: I got a
    Code:
    warning: suggest braces around initialization of subobject [-Wmissing-braces]
    warning: missing field 'struct member heret' initializer [-Wmissing-field-initializers]
    When brace initializing the structures. This was on the macs at my school with clang 900.0.39.2 (llvm 9.0)
    I thought it interesting because I was pretty certain that was well defined behavior, specified in the standard.
    Nevertheless, I looked and tbh, this is all I could find:
    If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
    Which I believe pretty much corroborates my assumptions. Although it is isn't as clear as I'd like.

    Google searching turned out confusing results such as this thread: c - How to remove the warning in gcc 4.6: missing initializer [-Wmissing-field-initializers]? - Stack Overflow

    To make matters more confusing, I read about an empty braced-enclosed list initializer, - structIdentifier = open_curly_brace-close curly_brace; -which is a thing in c++, but apparently can also be used in c, since not only worked but it shut up the compiler warnings altogether when I tried it.

    The whole thing might be a bug in Clang, as it seems to complain about missing braces first, which in turn leads to the missing field initialier warning.
    I don't know. My computer, running whatever version of GCC is in Debian testing, doesn't seem to have any issue whatsoever with the statement. /shrug.
    I will continue to use "open curly brace 0 close curly brace" as that is what I'm used to and seems natural, and will use -Wno-missing-field-initializers on the macs for now.


    NOTE: Please forgive the open_curly_brace statements. The forum wouldn't let me use actual curly braces without inserting code tags.
    I didn't want to so I opted for this alternative.
    printf("I'm a %s.\n", strrev("Dren"));

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 08-29-2015, 01:15 PM
  2. Replies: 43
    Last Post: 05-23-2013, 03:01 PM
  3. size of struct with pointers and function pointers
    By sdsjohnny in forum C Programming
    Replies: 3
    Last Post: 07-02-2010, 05:19 AM
  4. Storing function pointers in generic pointers
    By Boxknife in forum C Programming
    Replies: 6
    Last Post: 08-01-2009, 01:33 PM
  5. Pointers to objects -- passing and returning pointers
    By 1veedo in forum C++ Programming
    Replies: 4
    Last Post: 04-04-2008, 11:42 AM

Tags for this Thread