Link to home
Start Free TrialLog in
Avatar of dwortman
dwortmanFlag for United States of America

asked on

How to increment counter variables in ANSI C (Not C# or C++).

I have an interesting problem for the ANSI C coders out there.  We want to know how many times a master program has calculated when two of its variables have violated a certain limit (say outside of +/- 100).  One variable monitors a positive limit and the other a negative limit and each counts the number of minutes the limit stays in violation.  The master program then writes those variables (called High and Low) to a database which will be used by this code.  One of the variables (High or Low) will always be zero.  But here comes the tricky part. When either of the variables violate the limit for 10 through 14 minutes a variable called HighLow10-14 is incremented one time.  However, if the limit is still being violated for any minute in the 15 through 19 minute range another variable called HighLow15-19 is also incremented.  If the limit is still being violated at minute 20 a third variable called HighLow20 is incremented by 1 as well.  

Basically we are trying to record the number of times that a limit (High or Low) has been violated by 10 or more minutes and the  violation time broken down into 3 “buckets” if you will. There is a 10-14 minute bucket, a 15-19 minute bucket and a 20 bucket. Anything limit greater than 20 minutes is ignored.  When a High or Low variable goes back within +/- 100 limit it will automatically be reset to zero by the master program.  

This code runs every 4 seconds to check the High and Low variables of the master program.  At the end of the month the buckets are reset to zero for the start of the new month, which I will take care of.
Avatar of sarabande
sarabande
Flag of Luxembourg image

see the following

#include <time.h>

/* those variables must be defined and initialized in another .c file say in main.c */

extern int  HIGHLIM;
extern int  LOWLIM;
extern int V10TO14; 
extern int V15TO19; 
extern int VGE20;

void CountViolations(int high, int low)
{
    static time_t firsttime = 0;
    static time_t lasttime = 0;


    if (high > HIGHLIM || low < LOWLIM)
    {
        /* seconds since epoch */
        time_t now = time(NULL);
        int       elapsed = 0;
        if (lasttime == 0)
        {
            firsttime = now;
            lasttime = now;
            return;
        }
        elapsed = (int)(now - lasttime);

        /* count violations every minute */ 
        if (elapsed < 60)
            return;
        elapsed = (int)now - firsttime;
        if (elapsed > 600)
            V10TO14++;
        if (elapsed > 900)
            V15TO19++;
        if (elapsed > 1200)
            VGE20++;
        lasttime = now;
    }
    else
    {
        lasttime = 0;
        firsttime = 0;
    }
}

Open in new window


the counters can be monitored by any other module which defined or declared (extern) the counters.

Sara
Avatar of dwortman

ASKER

Sara,
Thanks for the information.  I will work with it today and might have to ask another question or two.

Dee
Sara,
The code you gave me works great but I need a “slight” modification.  This script runs every 4 seconds to check for high or low violations.  If the elapsed time is greater than 600 for the first time how would I stop it and write to a file?  I would need to do this for all three “time buckets”.   The output file I have in mind looks similar to the below:
00:12:22 V10TO14
05:21:02 V15TO19
06:12:22 VGE20
08:21:02 V15TO19

Thanks
you could do like

        elapsed = (int)now - firsttime;
        if (elapsed > 600)
        {
             if (0 == V10TO14++)
             {
                   struct stat fs = { 0 };
                   FILE * pflog;
                   if (stat("highlow.log", &fs) != 0)
                   {
                          pflog = fopen("highlow.log", "wt");
                    }
                   else 
                   {
                         pflog = fopen("highlow.log", "wa");
                   }
                   if (pflog)
                   (
                          char sztime[32] = { '\0' };
                          struct tm * ptm = localtime(&now);
                          strftime(sztime, sizeof(sztime), "%H:%M:%S V10TO14\n", ptm);
                          fwrite(sztime, 1, strlen(sztime),  pflog);
                          fclose (pflog);
                   }
               }
          } 

Open in new window

 

if you put the above into a little function you easily can call it for any of your counters.

Sara
Sara,

Could you please explain your snippet to me.  I do not see how it will write V10TO14 to the log file just one time and keep the elapsed time counting to elapsed time > 900 and so on.  I am no good at subroutines, could you give an example?

Thanks
i will move the code of the snippet into a function ('subroutine' is a fortran term as far as i remember. in c/c++ there are only functions) and add comments to explain the code.

// the function hasn't a return value, so the return type is void
// pass name of limit as a string argument for example "V10TO14"

void LogFirstLimitViolation(const char * szNameOfLimit)   
{
    // struct stat is a structure which contains info of a disk file
    // note, there is a type 'struct stat' and a function 'stat' 
    struct stat fs = { 0 };
    // that is pointer which is returned by fopen when opening thhe log file
    FILE * pflog;
    // with function stat we check whether the log file exists or Needs to be created
    if (stat("highlow.log", &fs) != 0)
    {
         // if we come here the log file doesn't exist
         // we open (create) the file as text and for write
         pflog = fopen("highlow.log", "wt");
    }
    else 
    {
          // we open the existing file in append mode
         pflog = fopen("highlow.log", "wa");
    }
    // if no error the pointer is not 0
    if (pflog)
    (   
        // build timestamp  
       char sztime[256] = { '\0' };
       time_t now = time(NULL);
       struct tm * ptm = localtime(&now);
       strftime(sztime, sizeof(sztime), "%H:%M:%S ", ptm);
       // add the name of the limit to the timestamp
       strcat(sztime, szNameOfLimit);
       // add linefeed to the log entry
       strcat(sztime, "\n");
       // write log entry
       fwrite(sztime, 1, strlen(sztime),  pflog);
       // close the file or it was locked
       fclose (pflog);
    }
}

Open in new window


put that code above your CountViolations function.

in the CountViolations function you now could call the new function like

        if (elapsed > 600)
            if (0 == V10TO14++) 
                  LogFirstLimitViolation("V10TO14");
        if (elapsed > 900)
            if (0 == V15TO19++) 
                  LogFirstLimitViolation("V15TO19");
        if (elapsed > 1200)
            if (0 == VGE20++) 
                  LogFirstLimitViolation("VGE20");

Open in new window


Sara
Sara,

Forgive me  for the Fortran reference but one of my main assignments is to maintain some Fortran legacy code that happens to use a lot of subroutines.   Thanks for your quick reply and the additional code and especially the comments.  I have got a prototype  working by modifying the code you have supplied.  In my prototype I was able to use brute force and ignorance to append a date to the .log file (highlow_yyyy-mm-dd.log) for example (please see attached file).   Note that "STRING1" is an internal string function of the compiler that I use. It would be nice to know a better way of doing this.  I will be in meetings today so tomorrow I will see what I can do with the new code you have supplied.
Thanks
snippet.txt
ASKER CERTIFIED SOLUTION
Avatar of sarabande
sarabande
Flag of Luxembourg image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sara,

Thanks for all of your help.  Your comments helped me learn a lot.