Classic static



  • One of the gems at my new workplace: 

    char* doubletostring(double d)
    {
      static int t=-1;
      static char s[16][100];

      if( ++t > 15 )
        t = 0;

      sprintf(s[t],"%0.15f",d);
      return s[t];
    }

    It's actually part of a bigger project (their *best way* of processing data in C++), containing: 3 files:
    - app.cpp = 40.722 lines (of spaghetti code)
    - app.h = 1.149 lines
    - main.cpp = 526 lines

    "Just look at the code to know how it works, it's pretty obvious". They have 250+ similar projects (3 files being the general pattern, 2.000-40.000 lines being the average size of the godly cpp file).

    They also have their own XBool class (True, False, Unknown), jackpot!

     

    Please kill me. Thank you in advance.



  • They have now discovered threading and are busy converting everything to be threadsafe.

    Thread-safety: Convert every static into a hashtable with the Thread ID as the key.



  • There are numbers you can call.

     

    DON'T KILL YOURSELF, IT'S NOT WORTH IT!



  • @GuntherVB said:

    They have now discovered threading and are busy converting everything to be threadsafe.

    Thread-safety: Convert every static into a hashtable with the Thread ID as the key.

     

    Thank you for illuminating me. I've always tried to do it avoiding shared resources and semaphores, but this is truly brillant!

    As to the original post: OMG! How many WTFs can one count there? There is of course the inherent problem of interrupting the increment, or calling it from more than 16 threads at the same time. There is the name, which suggests it should work for any double, but which insists on this ridiculous 0.15f format, so anything really large or really small will need another format. Then there is the fact that this utility function is so small, it could be inlined at the place of calling, thereby probably improving thread-safety (unless the caller itself isn't thread-safe, which would be another WTF).

    And now for something completely different: did you notice that WTF can be used as a countable noun, i.e. you can say one WTF, two WTFs, three WTFs, etc., but only when it means what-the-fuck, not when it means worse-than-failure?



  • @Morbii said:


    DON'T KILL YOURSELF, IT'S NOT WORTH IT!

    Oh yes it is.

    void XString::ToDigitOnly()
    {
     const char* pLkup=(const char*)*this;
     char *pNew = new char[this->length()+1];

     *pNew=0;
     char *ptr=pNew;
     while(*pLkup)
     {
       if(isdigit(*pLkup))
       { *ptr=*pLkup;
         ptr++;
         *ptr=0;
       }
       pLkup++;
     }

     XString newstr(pNew);
     delete [] pNew;
     *this=newstr;
    }

    Plenty more where that came from!



  • It's not thread safe, it's 'multi call' safe:

    printf("%s %s\n", doubletostring(0.1), doubletostring(0.2));

    (That up to 16 times)

     

    I'm trying to think up more horrible sollutions... but I can't.

     

    Oh, and it's C++ so convert that code to use the standard string classes ;) 


  • Discourse touched me in a no-no place

     @Daid said:

    <contrived example>

    I'm trying to think up more horrible sollutions... but I can't.

    Something perhaps not as contrived: 

    <font face="courier new,courier">const char* old = doubletostring(3.14);</font>

    <font face="courier new,courier">/* lots and lots of code, where doubletostring() may, or may not be called 16 or more times, possibly in calls to other functions.. */</font>

    <font face="courier new,courier">assert(!strcmp(old, doubletostring(3.14)));  /* may, or may not, assert() */</font>


     



  • @GuntherVB said:

    char* doubletostring(double d)

    Silver lining: the "double d" bit.



  • @GuntherVB said:

    They have now discovered threading and are busy converting everything to be threadsafe.

    Thread-safety: Convert every static into a hashtable with the Thread ID as the key.

    Now that is truly awesome. I couldn't bring up this idea myself. At least not under the topic of thread safety.



  • @GuntherVB said:

    They have now discovered threading and are busy converting everything to be threadsafe.

    Thread-safety: Convert every static into a hashtable with the Thread ID as the key.

     

     

    Of course, this requires a threadsafe hashtable.

    Can't wait to see it. 

     


  • Discourse touched me in a no-no place

    @Hatshepsut said:

    Of course, this requires a threadsafe hashtable.

    Can't wait to see it. 

    And your problem with mutexes is...?


  • @PJH said:

    @Hatshepsut said:

    Of course, this requires a threadsafe hashtable.

    Can't wait to see it. 

    And your problem with mutexes is...?
    Some twisted mind figured that using a hashtable is better then blocking execution of some threa[d/t]?



  • @PJH said:

    @Hatshepsut said:

    Of course, this requires a threadsafe hashtable.

    Can't wait to see it. 

    And your problem with mutexes is...?

    ... that you don't want their heads to explode


  • ♿ (Parody)

    @GuntherVB said:

    @PJH said:

    And your problem with mutexes is...?

    ... that you don't want their heads to explode

     

    But that sounds like a great solution for these WTFs! 



  • Unless.. they invent their own mutexes, dear lord.



  • The only WTF I can see is that this is unnecessarily specialized. Out of a singlethreaded game engine (that will never be multithread-able, as MOST of its code relies on certain globals):

    /*
    ============
    va

    does a varargs printf into a temp buffer, so I don't need to have
    varargs versions of all text functions.
    FIXME: make this buffer size safe someday
    ============
    */
    char *va(const char *format, ...)
    {
            va_list argptr;
            // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
            static char string[8][1024], *s;
            static int stringindex = 0;

            s = string[stringindex];
            stringindex = (stringindex + 1) & 7;
            va_start (argptr, format);
            dpvsnprintf (s, sizeof (string[0]), format,argptr);
            va_end (argptr);

            return s;
    }

    Note: dpvsnprintf is just a de-WTF-ed alias to vsnprintf (on some platforms, snprintf style functions don't ensure a terminating \0 when the buffer was too short, but dpsnprintf functions always ensure that).

    Typical use of va():

    FILE *f = fopen(va("%s.png", basename), "rb");

    but yes, it is easy to make code using it that breaks. Like, a function foo(const char *input) that uses va() over 7 times and then still wants to use the input string, and calling foo(va(...)). So it is kinda WTF - but a necessary evil in C. In more modern languages (even C++), such code can be always avoided by a little bit of extra typing, but no extra thinking or memory management...

    FILE *f = fopen((basename + ".png").c_str(), "rb");

    or even:

    FILE *f = fopen((std::ostringstream() << modelname << "_" << i << ".png").str().c_str(), "rb");
    instead of
    FILE *f = fopen(va("%s_%d.png", modelname, i), "rb");

    So, C++ does provide a working replacement for va(), while in C it is not possible to make a good one. And actually, va() could easily be implemented in a good way in C++, returning a std::string object instead of a const char *.



  • You laugh, but I remember doing this once in my heydey for an exception/error log.  It had to be bolted on to the original design because the original design didn't account for any errors happening (ha ha) in the worker threads of a multi-threaded app.

    Of course that app has since been totally redesigned with more appropriate logging mechanisms, but nevertheless, the thread-hash-table actually did the trick at the time and helped find a number of bugs and a couple of deadlocks. 

    <hints id="hah_hints"></hints>


  • So Gunther, when do you reckon you'll be leaving?



  • More to the point, when can we expect to see your submission to the main site?


Log in to reply