Question

Compilers detect unused variable within the scope of a function. However, I found there are many variables, defined inside a structure, which are never read (but may have been written many times). Is there any tool/analyzer or even compiler flags to detect such unused variables?

Example: For example, in the following structure:

typedef struct jj_t {
    int count;
    int *list;
} jj;

Analyzer may find that count is never read anywhere in the code.

My analyze of my code, shows this frequently happens! This was my fault, but it maybe the common case for the applications developed by different users over the years. Removing these variable may significantly reduces memory usage. I just need a tool for detecting such variables and I will manually remove them.

Thanks in advance.

Was it helpful?

Solution

I can give one solution.

But:

  1. The effort is probably much bigger than checking by hand. Almost every good IDE for programmers allows you to see all references to a given variable.

  2. This probably won't work in every case, you'll need to specialize for some types.

  3. This will be collected by single program run.

The idea is to wrap your data types. With such encapsulation you can count every read operation. See:

template <class T, class Parent, int NO=1>
class TReadDetector {
public:
   struct Data {
      bool touched;
      Data () : touched(false) {}  
      ~Data ()  {
        if (!touched) 
          std::cerr << typeid(*this).name() << ": not read!!!\n" << std::endl;
      }  
   };
   static Data  data;
   TReadDetector () {}
   TReadDetector (const T& t) : t(t) {}
   operator T () const {    data.touched = true; return t; }
   TReadDetector& operator = (const T& t) { this->t = t; }
private:
   T t;
};

template <class T, class Parent, int NO>
typename TReadDetector<T,Parent,NO>::Data  
                       TReadDetector<T,Parent,NO>::data;

And usage:

Instead of:

struct A {
  int a;
  int b;
};

DO this:

struct A {
  TReadDetector<int,A, 1> a;
  TReadDetector<int,A, 2> b;
};


int main() {
  A a;
  a.a = 7;
  a.b = 8;
  std::cout << a.a << std::endl;
  std::cout << TReadDetector<int,A, 1>::data.touched << std::endl;
  std::cout << TReadDetector<int,A, 2>::data.touched << std::endl;
  std::cout << "main() ended" << std::endl;
};

It will results in:

7
1
0
main() ended
N13TReadDetectorIi1ALi2EE4DataE: not read!!!

Notice last line printed after main(). You can collect this data to some external file.

OTHER TIPS

Any analysis would have to be accross translation units.

In practice, unlike you, I've never found this to be a problem. About the only solution I can think of off hand is to delete the members one by one, and see if the entire application still compiles.

Removing the field from the structure can be dangerous in few cases if we have used the structure like,

typedef struct jj_t {     int count;     int *list; } jj; 

jj *ptr = malloc (...);

//....

*ptr = 5; // NAIVE (but I have seen usage like this).
          // Actually you are not modifying count, count was already deleted.

So, very hard to do the analysis you were asking for.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top