1<?xml version="1.0" ?> 2<notes> 3The nature of the C language and its preprocessor can result in pathological 4cases that can confuse the <em>CScout</em> analysis and substitution engine. 5In all cases the confusion only results in erroneous analysis or 6substitutions of the particular identifiers and will not affect other 7parts of the code. 8In some cases you can even slightly modify your workspace definition 9or code to ensure <em>CScout</em> works as you intend. 10The following cases are the most important in recognising and substituting 11identifiers: 12 13<ol> 14<li> Conditional compilation<p> 15Some programs have parts of them compiled under conditional preprocessor 16directives. 17Consider the following example: 18 19<fmtcode ext="c"> 20#ifdef unix 21#include <unistd.h> 22#define erase_file(x) unlink(x) 23#endif 24 25#ifdef WIN32 26#include <windows.h> 27#define erase_file(x) DeleteFile(x) 28#endif 29 30main(int argc, char *argv[]) 31{ 32 erase_file(argv[1]); 33} 34</fmtcode> 35 36As humans we can understand that <code>erase_file</code> occurs three times 37within the file. 38However, because <em>CScout</em> preprocesses the file following the 39C preprocessor semantics, it will typically match only two instances. 40In some cases you can get around this problem by defining macros that will 41ensure that all code inside conditional directives gets processed. 42In other cases this will result in errors (e.g. a duplicate macro definition 43in the above example). 44In such cases you can include in your workspace the same project multiple 45times, each time with a different set of defined macros. 46<pre> 47workspace example { 48 project idtest { 49 define DEBUG 1 50 define TEST 1 51 file idtest.c util.c 52 } 53 project idtest2 { 54 define NDEBUG 1 55 define PRODUCTION 56 file idtest.c util.c 57} 58</pre> 59<li> Partial coverage of macro use <p> 60Consider the following example: 61<fmtcode ext="c"> 62struct s1 { 63 int id; 64} a; 65 66struct s2 { 67 char id; 68} b; 69 70struct s3 { 71 double id; 72} c; 73 74#define getid(x) ((x)->id) 75 76main() 77{ 78 printf("%d %c", getid(a), getid(b)); 79} 80</fmtcode> 81In the above example, changing an <code>id</code> instance should 82also change the other three instances. 83However, <em>CScout</em> will not associate the member of 84<code>s3</code> with the identifier appearing in the <code>getid</code> 85macro or the 86<code>s1</code> or <code>s2</code> structures, 87because there is no <code>getid</code> macro invocation to link them together. 88If e.g. <code>id</code> is replaced with <code>val</code> 89the program will compile and function correctly, 90but when one tries to access the <code>c</code> struture's member 91in the future using <code>getid</code> an error will result. 92 93<fmtcode ext="c"> 94struct s1 { 95 int val; 96} a; 97 98struct s2 { 99 char val; 100} b; 101 102struct s3 { 103 double id; 104} c; 105 106#define getid(x) ((x)->val) 107 108main() 109{ 110 printf("%d %c", getid(a), getid(b)); /* OK */ 111 printf(" %g", getid(c)); /* New statement: error */ 112} 113</fmtcode> 114 115To avoid this (rare) problem you can introduce dummy macro invocations 116of the form: 117 118<fmtcode ext="c"> 119#ifdef CSCOUT 120 (void)getid(d) 121#endif 122</fmtcode> 123 124 125<li> Undefined macros<p> 126We employ a heuristic classifying all instances of an undefined macro 127as being the same identifier. 128Thus in the following sequence <code>foo</code> will match all 129three macro instances: 130<fmtcode ext="c"> 131#undef foo 132 133#ifdef foo 134#endif 135 136#ifdef foo 137#endif 138 139#define foo 1 140</fmtcode> 141In most cases this is what you want, but there may be cases where the macro 142appears in different files and with a different meaning. 143In such cases the undefined instances of the macro will erroneously 144match the defined instance. 145</ol> 146<p> 147In addition, the analysis of functions can be confused by the following 148situations. 149<ol> 150<li> Functions getting called through function pointers will not 151appear in the call graphs. 152This is a common limitation of static call analysis.</li> 153<li> Function-like macros called from inside function bodies that 154were generated by macro expansion will not be registered as calls.</li> 155<li> Non-function like macros that expand into function calls will 156not appear in the call graph; the corresponding functions will appear 157to be called by the function containing the macro.</li> 158</ol> 159<p> 160Finally, because function argument refactoring works at a higher level 161thann simple identifiers, the following limitations hold. 162<ol> 163<li>When a function call's arguments macro-expand into unballanced brackets 164or into multiple function arguments the replacement can misbehave.</li> 165<li>When there is not a one-to-one correspondence between a 166function's name and its associated identifier 167(i.e. when the function's name is generated through macro-token concatenation) 168the function argument refactoring is not offered as an option. 169</li> 170</ol> 171</notes> 172