First of all, the preprocessor token concatenation feature can result in C identifiers that are composed of multiple CScout identifiers. Consider the following example, which uses a macro to define a number of different functions. (Yes, I am familiar with the C++ templates, this is just an example.)
#define typefun(name, type, op) \ type type ## _ ## name(type a, type b) { return a op b; } typefun(add, int, +) typefun(sub, int, -) typefun(mul, int, *) typefun(div, int, /) typefun(add, double, +) typefun(sub, double, -) typefun(mul, double, *) typefun(div, double, /) main() { printf("%d\n", int_add(5, 4)); printf("%g\n", double_mul(3.14, 2.0)); }In the CScout environment the
int_add
C identifier is
actually composed of three separate parts:
int
_
add
int
identifier into integer
would change it in five different places: the argument to the four
typefun
macro invocations, and the part of int_add
.
In addition, preprocessor macro definitions can confuse the notion of the C scope, bringing together scopes that would be considered separate in the context of the C language-proper. Consider the following (slightly contrived) example:
struct foo { int foo; }; struct bar { int foo; }; #define getpart(tag, name) (((struct tag *)p)->name) #define getfoo(var) (var.foo) #define get(name) (name(0) + ((struct name *)p)->name) #define conditional(x) do {if (!x(0)) goto x; return x(0);} while(0) int foo(void *p) { struct foo f; struct bar b; foo: if (p && getpart(foo, foo)) return getpart(bar, foo); else if (getfoo(f)) return get(foo); else if (getfoo(b)) conditional(foo); else return 0; }The identifier
foo
is occuring in a number of different
scopes:
foo
identifier,
CScout will change all the instances marked below,
in order to obtain a program that has the same meaning as the original
one.
Identifier foo: test.c(Use the tab key to move to each marked element.) struct foo {
|
#define macro() middlemacro() #define middlemacro() innemacro() #define innemacro() function1() function1() {} function2() {} main() { macro(); function2(); function3(); printf("Hello"); }The corresponding call graph is as follows:
Note that in CScout functions are separate entities from identifiers. The name of a function can consist of multiple identifiers; an identifier can exist in more than one function names.
For instance,
the page for the _
(underscore) identifier in the
typefun
macro example we saw earlier
will appear as follows.
Identifier: _CScout 2.0 - 2004/07/31 12:37:12 |
Note how each function name is composed of three separate parts,
and that this instance of the _
identifier occurs in
8 different function names.
One important feature of CScout concerning files has to do with the handling of files that are exact copies of each other. These may occur in the building of a large system for the sake of convenience; for example, one header file may be copied to various parts of the source code tree. CScout will locate identical files and group them together when reporting a file's details. Identifiers occuring in the same position of two identical files are considered equivalent; if you change the name of one of them the name of the other will also change. Moreover, when CScout reports unused identifiers it takes into account uses of an identifier from all instances of the identical files, not just one of them.
Contents | « Previous Next (The Web Interface) » |