0

I am currently a Java programmer doing some work in C for a class, and I've been struggling a lot with the differences between the two. Currently, I am trying to add functionality with compiler hooks to count the time that is spent within each function of the program that is being executed. My struggle for this is that my solution is to use a stack, and I'm having trouble instantiating (if that's even the right word to use?) the stack since I can't add a main method or something of that sort to create it at the beginning. Here is my code now:

#include <stdio.h>
#include <time.h>
#include "mystack.h"

static stack_t* entry_times=create_stack(500);
static unsigned int count_entered=0;
static unsigned int count_completed=0;


__attribute__((no_instrument_function))
void __cyg_profile_func_enter(void *this_fn, void *call_site){
    count_entered++;
    time_t start_time;
    time(&start_time);
    stack_enqueue(entry_times, start_time);
    printf("Total Functions Entered: %d\n", count_entered);

}

__attribute__((no_instrument_function))
void __cyg_profile_func_exit(void *this_fn, void *call_site){

    time_t end_time;
    time(&end_time);
    time_t start_time = stack_dequeue(entry_times);
    double difference = difftime(end_time, start_time);
    count_completed++;
    printf("Time in Function: %d\n", difference);

}

Right now, when I try to compile this code, I am getting a "initializer element is not constant" error point to the line where I create my entry_times stack. How can I solve this error, or refactor my code to prevent this issue?

I'm sorry if this is a duplicate topic, I have done a fair amount of searching, and I suspect I simply do not know what to actually search for to find the information that I am looking for.

Mike
  • 4,041
  • 6
  • 20
  • 37
katamaster818
  • 341
  • 2
  • 12
  • 1
    @Someprogrammerdude: OP didn't invent those double-underscore names--they are names decided by the implementation. So it's all good. – John Zwinck Oct 10 '18 at 05:58
  • See https://stackoverflow.com/questions/3025050/error-initializer-element-is-not-constant-when-trying-to-initialize-variable-w and https://stackoverflow.com/questions/23040769/initializer-not-constant-on-global-variable – John Zwinck Oct 10 '18 at 06:00
  • @JohnZwinck I actually think I looked at one of these already - correct me if I am wrong, but it seems as though these suggest two solutions: 1) I can have an initializer method, or 2) I can use #define to make it a constant. I'm struggling with understanding how to apply either of these to this specific scenario as I don't think I can have an init method for compiler prehooks? And I can't seem to understand how to create a struct using #define, I have spent the last half hour trying to do this unsuccessfully. – katamaster818 Oct 10 '18 at 06:06
  • 1
    Maybe you're looking for C++ — it allows you to use functions in initializers at global scope. – Jonathan Leffler Oct 10 '18 at 06:12
  • This assignment must be completed in C, so I don't think that's the way I'm supposed to go with this. – katamaster818 Oct 10 '18 at 06:14
  • 1
    Since you're already using GCC specific constructs (`__attribute__`) then perhaps to create a "constructor" function that will be called before `main` and could do any initialization you need? See [this list of common function attributes](https://gcc.gnu.org/onlinedocs/gcc-8.2.0/gcc/Common-Function-Attributes.html#Common-Function-Attributes) for more information about it. – Some programmer dude Oct 10 '18 at 06:17
  • @Someprogrammerdude Thanks, this actually worked really well, was exactly what I was looking for! – katamaster818 Oct 10 '18 at 06:45

2 Answers2

3

Why you are getting error is explained in John Zwinck's links, but how to solve it for you, it depends. You could create constructor function which does initialisation for you e.g.

static stack_t* entry_times;
__attribute__((constructor))
void my_init(){
    entry_times=create_stack(500);
}

or you could create a wrapper function around it

stack_t* my_entry_times(){
    static stack_t* entry_times;
    if (!entry_times) {
        entry_times=create_stack(500);
    }
    return entry_times;
}

and use my_entry_times() instead of entry_times in code

Mindaugas
  • 1,707
  • 13
  • 20
0

In C you can't call a function when initialising a variable in file or global scope.

You should be calling malloc to allocate some memory for you, something like this:

static stack_t* entry_times = NULL;

entry_times = (stack_t*)malloc(500 * sizeof(stack_t));

That will give you 500 instances of stack_t.

You need to free when you no longer need the memory.

EDIT:

Here is my solution for your problem - not pretty but if you only have those two functions, you are quite restricted...

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mystack.h"

static stack_t* entry_times=NULL;
static unsigned int count_entered=0;
static unsigned int count_completed=0;


__attribute__((no_instrument_function))
void __cyg_profile_func_enter(void *this_fn, void *call_site){
    if (entry_times == NULL) {
        entry_times = (stack_t *)malloc(500 * sizeof(stack_t));
    }
    count_entered++;
    time_t start_time;
    time(&start_time);
    stack_enqueue(entry_times, start_time);
    printf("Total Functions Entered: %d\n", count_entered);

}

__attribute__((no_instrument_function))
void __cyg_profile_func_exit(void *this_fn, void *call_site){

    time_t end_time;
    time(&end_time);
    time_t start_time = stack_dequeue(entry_times);
    double difference = difftime(end_time, start_time);
    count_completed++;
    if (entry_times != NULL) {
        free(entry_times);
        entry_times = NULL;
    }
    printf("Time in Function: %d\n", difference);

}
NeRa
  • 101
  • 5