1 procedure calls memory allocation, calling conventions, parameters, environments, and cute tricks
TRANSCRIPT
1
Procedure Calls
Memory allocation, calling conventions, parameters, environments, and cute tricks
2
Procedure calls
How can one function (procedure) "call" another one?
How can we pass parameter values?
How can we return a result?
Each procedure requires its own environment and may call other procedures
May be many call points
main() {int a, b, c;b = sub1(a);c = sub2(a,b);...
}int sub1(x) {
int z = (x+1)/x;return sqrt(z);
}sub2(x,y) { int z = sub1(y);
return x + y*z;}
3
Calling Sequence: caller
What must be done when a procedure is invoked?
Before Call, the caller does:
1. allocate space for a return value, if there is one
2. put return address into a known location
3. prepare actual parameter values for formal parameters
4. save any variables held in registers back to memory
5. maybe save other registers (depends on calling convention)
6. execute a "jump" instruction to the callee's code
Not necessarily in this order.
4
Caller builds stack frame for callee
Caller starts the stack frame for new procedure.
Dynamic Link
Return value
Return Address
Parameters
caller's stack frame
first part of stack frame for the callee
stack pointer
old stack pointer
5
Calling Sequence: callee
When a procedure (callee) is invoked, it does:
1. allocates space for its local variables and temps
2. saves any registers that it needs, if required.
3. adjust the frame pointer and stack pointer (in a stack based environment)
By convention, the callee does most of the work in the calling sequence. There are two reasons:
1. there may be many call points to a single procedure. Any instructions done on the caller's side must be duplicated at each call point, making the program larger.
2. the callee knows what registers it will use and how much stack space it needs, so callee should be responsible for saving/restoring registers and managing stack space.
6
Callee increases his stack frame
Callee adds space for local variables, temporaries, and "callee saves" register. Dynamic Link
Return value
Return Address
Parameters
caller's stack frame
Locals & Temporaries
Callee saved data
stack pointer
frame pointer
7
Calling Sequence: on return
When a procedure "returns" (Epilog): save any persistent (static) local variables that are in
registers if there is a return value, put it in a specified location free storage used by callee's local variables & temps restore any saved registers branch to a return address (next instruction of caller)
8
Calling Sequence: example
save value of a to its memory location
save registers and P.C. put values for sub's
parameters on the stack put return address on
stack add dynamic link to
caller's stack frame branch to sub sub allocates space for x
int a; /* global */int sub( u, v ) {
if ( v == 0 )return u;
int x = u % v;return x;
}
int caller( ) {a = readInt();result =
sub(4+a*a*a, a);
temporary value
9
Activation Record
Activation record or frame of a procedure is a block of memory used for parameter values, return address, local variables, temporary results, and bookkeeping (dynamic link, static link).
Temporaries
Local variables
Return Address
Parameters and Returns
Temporaries
Local variables
Dynamic Link
Parameters & Returns
Simple Activation Record (static allocation)
Return Address
Stack Dynamic Activation Record
stack
10
Simple Static Allocation
Both code and data areas are allocated statically. Early FORTRAN used this method for efficiency.
MAIN
SUB1
SUB2
SUB3
Code
Local variables
Return address
Parameters
Locals & Temps
Locals & Temps
Locals & Temps
Data
MAIN
SUB1
SUB2
SUB3
Return address
Parameters
Return address
Parameters
11
Stack Dynamic Allocation (1)
Activation records are pushed onto a stack
main
main is running
main calls sub1
main
sub1
main() {int a, b, c;b = sub1(a);c = sub2(a,b);...}sub1(x) { ... }sub2(x,y) { ... int z = sub3();
free space
free space Temporaries
Local variables
Return address
Dynamic link
Parameters
frame pointer
12
Stack Dynamic Allocation (2)
Activation records are pushed onto the stack
main
sub1 returns
main calls sub2
main
sub2
main() {int a, b, c;b = sub1(a);c = sub2(a,b);...}sub1(x) { ... }sub2(x,y) { ... int z = sub3();
free space
free space
sub2 calls sub3
main
sub2
free space
sub3
13
Comparison of Static & Dynamic Alloc
Advantages of Static Allocation addresses of local vars are known at compile/load time.
This makes addressing more efficient. instructions to implement procedure calls are simpler simplifies saving of local data between calls
Advantages of Dynamic Allocation needed to implement recursion uses less memory other?
14
How Can You Detect Static Allocation? Originally FORTRAN used static allocation.
Fortran "SAVE" statement was superfluous! Now some implementations use stack dynamic
allocation, even for Fortran 77.
Q: How can you tell if static allocation is being used?
SUBROUTINE ACCUM(X)REAL X, SUMDATA SUM /0.0/SAVE SUMSUM = SUM + XENDPROGRAM MAINACCUM(1.0)ACCUM(2.5)...etc...
"SAVE" means that the value of this local variable should be saved between calls, i.e. static allocation.
However, in FORTRAN IV all local variables were static!
15
How Can You Detect? (cont.)
Q: How can you tell if static allocation is being used?
SUBROUTINE STATICREAL X, SUMDATA SUM /0.0/IF (SUM .EQ. 1) THEN WRITE(*,*) 'STATIC'ENDIFSUM = 1ENDPROGRAM MAINCALL STATICCALL JUNKSTACKCALL STATIC...etc...
DATA SUM /0.0/ initializes SUM to 0.
In a static environment, this is done only once, so second time, the value of SUM will be 1.
JUNKSTACK is some other procedure that puts junk in local variables, to change the old contents of the stack (if dynamic allocation).
16
Why use the stack?
Many lexically typed languages use the stack for parameter values, local variables, temps, etc.
Why use stack instead of registers? Observation by Michael Scott:
The use of the stack to pass arguments reflects the technology of the 1970s, when register sets were significantly smaller and memory access was significantly faster (in comparison to processor speed). [Programming Language Pragmatics, p. 438]
17
Frame Pointer In stack dynamic allocation, the actual addresses of
data on the stack aren't known at compile time. Addresses are given relative to a frame pointer (fp), or
environment pointer (ep), usually kept in a register.
main main
sub1
main() {int a, b, c;b = sub1(a);c = sub2(a,b);...}sub1(x) {int u,v,w; u =sub2(u-v,w);
free space
free space
frame pointer
18
Frame Pointer (2) For example, addresses of the local variables u, v, w might be referred
to as: (fp)+8, (fp)+12, (fp)+16 This is called displacement addressing
main
sub1
main() {int a, b, c;b = sub1(a);c = sub2(a,b);...}sub1(x) {int u,v,w; u =sub2(u-v,w);
free space
frame pointer
StackTemporary
values
u-v
u
Return address
Dynamic link
Parameters
v
w
stack pointer
19
Example: GNU C on the MIPS cpuThe MIPS cpu is a RISC processor with 32 general registers (r0 - r31) and several floating point registers (f0 - ...).
Registers are divided into 2 groups:
caller-saves registers: caller is responsible for saving any values in these registers. The callee can use these without saving old value.
callee-saves registers: callee is responsible for saving/restoring values in these registers before/after using them.
The compiler uses callee-saves registers for local variables and other long-lived items, and uses caller-saves registers for transient values such as loop indices. This minimizes "register saves" overhead in procedure calls.
Registers are used for special values:
r31 = return address r4-r7 = first 4 scalar parameters
r30 = frame pointer (or f12-f15 for f.p. parameters)
r29 = stack pointer
20
Languages and Environments
Languages differ on where activation records reside:
Static allocation: Fortran (before Fortran 90): all data, including activation
records, are statically allocated. Heap-oriented:
dynamically typed and functional languages: Scheme, ML, Smalltalk. Almost all data, including activation records, are allocated on heap.
Multiple areas: statically typed languages (C, Pascal, Algol, ...):
activation records on stack, data can be anywhere.
21
Example in C
int x;void p( int y) { int i = x; char c; ...}void q ( int a) { int x; p(1);}main( ) { q(2); return 0;}
Show the contents of the stack when p is activated.
22
Activation record of p:
23
Nested Procedures
Some languages allow procedures to be nested inside other procedures.
Pascal and Ada are examples
Inner procedure is "known" only in the scope of outer procedure.
Inner procedure can access variables of the outer procedure (static scope rules).
Procedure outer(p: real)var x, y: real;begin
Function f1( ): realbegin
return x*x;end;Function f2( ): realvar x,y: real;begin
x := 5;y := f1( );return y;
end;begin (* outer *)
x := 10;y := f2( ); (* =? *)
24
Nested Procedures and non-local variables
active procedure needs to be able to locate the frame of lexically enclosing scopes ("parent" scope).
Outer procedure must be somewhere on the stack, but it may be buried far below the current frame.
The lexically enclosing procedure must be on the stack, because "inner" procedure can only be called from within the "outer" procedure.
To find the lexically enclosing scope, we need another pointer -- called the static link or access link.
25
Nested Procedures Example (Ada)
procedure outer is x: integer;
procedure p (y: integer) isbegin
return y * x;end p;procedure r(a: integer) is x: float;begin p(a); ...
end r;begin r(1);end q;
Where is x ???
26© 2003 Brooks/Cole - Thomson Learning™
Environment during exec of p
27
"Closure"
A reference to a procedure along with its referencing environment is called a "closure".
Closures are important in languages that allow functions to be arguments or values of variables.
int main( ) {double a = 10, b = 3;double x = 0.5; dy = deriv( fun, x );
double fun(x) {return a*x + b;
}}
/* procedure that has a * function as parameter */double deriv( f, x) {
double a = 1, b = 2;double df;double dx = 1.0E-6;df = (f(x+dx)-f(x))/dx;
}
needs values of a and b
28
Two Methods for Factorial
In a stack dynamic environment, which is more efficient?
int factorial(int n) {if ( n <= 1 ) return 1;return n*factorial(n-1);
}
int factorial(int n) {int fact = 1;while( n > 1 ) {
fact = fact * n;n = n - 1;
}}
29
Parameter Passing Methods
Call by value: actual parameter values are copied into location of formal parameters.
Call by reference: a reference to the storage location of calling argument is passed to parameter.
Call by value-result: actual parameter values are copied to location of formal parameters; on return the procedure's parameter values are copied back to location of calling arguments.
Call by name: parameters are evaluated in the caller's environment every time they are accessed within a procedure.
30
Call by Value
Advantages: variables can be accessed directly in callee's stack frame prevents side-effects
Disadvantages: time-consuming to copy large data structures. requires additional memory for copy. cannot return a value by means of parameters -- but for reference
data types you can change what the param points to
int main() {int x = 10, y = 20;swap(x, y);/* no change!
x == 10, y == 20 */
Dynamic link
y = 20
Return address
x = 10
param1 = 10
param2 = 20
main
swap
31
Call by Reference
Advantages: avoids time & space overhead of copying data structures programmer can return results using parameters
Disadvantages: can cause accidental side effects; can produce aliases access to formal parameters is slower (for simple data types)
since callee must access value indirectly through address
int main() {int x = 10, y = 20;swap(x, y);/* changed!
x == 10, y == 20 */
Dynamic link
y = 20
Return address
x = 10
param1
param2
main
swap
points to storage addr.
32
Call by Value-Result
Advantages: programmer can return results using parameters direct (offset) addressing of formal parameters
Disadvantages: requires extra time and stack space to copy values results may depend on the order that values are copied
int main() {int x = 10, y = 20;swap(x, y);/* change!
x == 20, y == 10 */
Dynamic link
y = 20
Return address
x = 10
param1 = 10
param2 = 20
main
swap
33
Call by Name
computationally expensive and inefficient due to need to re-evaluate formal parameters for each access.
not used in any mainstream languages C pre-processor macros mimic behavior of call by
name
#define SQUARE(X) ((X)*(X))
int main() {double x = 1.0;double u = SQUARE(sin(x)); // sin(x) is called
twicedouble v = SQUARE(x++); // v = (x++)*(x++) = 2
// now x = 3.
34
Exercise: call by what?
Describe how you could determine whether parameters to a procedure were passed by reference, value, or value-result.
Write a short C or C++ program to illustrate the idea.
int main( ) {initializefun( arguments );analyze and printconclusion.
void fun( params ) {
}
35
Passing an Array as Parameter (1)
When we pass an array as parameter, what value(s) are passed?
For example, in C:int main( ) {
int x[100];readdata(100, x);sumdata(100, x);
void readdata(int count,int x[ ] ) {
x[1] = 10;}
In C, an array variable is a reference (pointer) to the start of the array.
Only the array address (4 B) is passed as parameter.
36
Passing an Array as Parameter (2)
This explains why a function can change the values of array elements, even though C uses call by value.
Both of these codes are equivalent:// declare x as arrayint sumdata( int count,
int x[ ] ) {int k, sum=0;for(k=0; k<count; k++)
sum += x[k];
// declare x as pointervoid sumdata( int count,
int *x ) {int k=0, sum = 0;while(k++ < count) {
sum += *x;x++;
}
increment x to point to next array element.
37
Parameter Passing Methods inMajor Languages
38
Fortran
Fortran usually uses call by reference. some implementations use call by value-result for
simple parameters.
SUBROUTINE SWAP(A,B)REAL A, B, TEMPTEMP = AA = BB = TEMPRETURNEND
PROGRAM MAINREAL X, YX = 10.0Y = 20.0CALL SWAP(X, Y)! now X=20, Y=10
39
Call by Reference: Fortran Bug
Fortran uses call by reference In some early implementations, literal constants are
stored in a (shared) static memory location. Some early compilers would change the value of a
numeric constant that was used as parameter!
Program MainREAL X, YX = 10.0CALL SWAP(X, 5.0)! 5.0 was changed to 10.0Y = 2.0*5.0! Y is 20.
SUBROUTINE SWAP(A,B)REAL A, B, TEMPTEMP = AA = BB = TEMPRETURNEND
40
C and Java
C and Java always pass parameters by value. sometimes it appears to pass by reference when
passing a variable of reference type (Java), or a pointer (C).
void sub1(int *n) {// change arg to 1000*n = 1000;// this has no effect// on the callern = n + 1000;
}
int main() {int a = 0;sub1(&a);// now a == 1000
41
Call by Value in C
int main() {int x = 10, y = 20;swap(x, y);/* no change!
x == 10, y == 20 */
void swap(int a, int b) {int temp = a;a = b;b = temp;
}
int n = 0;scanf("%d", n);
/* no change! n = 0 */
int n = 0;scanf("%d", &n);
/* n changed! */
42
Swap that works!
int main() {int x = 10, y = 20;swap(x, y);/* no change!
x == 10, y == 20 */
void swap(int a, int b) {int temp = a;a = b;b = temp;
}
int main() {int x = 10, y = 20;swap( &x, &y );/* changed!
x == 20, y == 10 */
void swap(int* a, int* b) {
int temp = *a;*a = *b;*b = temp;
}
In C, to emulate call by reference use pointers to args.
43
Array parameters in C and Java
In C an array name is passed as a pointer; in Java an array name is a reference to array object.
In both C and Java, a procedure can change the elements of an array. But not the array reference.
public void zero( int [] x ) {// this sets the caller's array to all zerofor(int k=0; k<x.length; k++) x[k] = 0;// this also sets caller's array to all zeroArrays.fill( x, 0);// this has no effect on the caller's argumentx = new int[100];// no effect on caller (anonymous array)x = new int[] { 0, 0, 0, 0, 0 };
}
44
Parameter Passing in C++
Parameters can be passed by value or reference C++ uses "&" (reference) on formal parameter type.
// C/C++ pass by valuevoid swap(int a, int b){ int temp;
temp = a; a = b;b = temp;
}
int main() {int n = 10, m = 20;swap(n, m);/* no effect! */
// C++ pass by refvoid swap(int& a, int& b){ int temp;
temp = a; a = b;b = temp;
}
int main() {int n = 10, m = 20;swap(n, m);/* n, m swapped! */
45
const Parameters in C and C++
C/C++ supports "const" for read-only parameters, which is enforced by compiler.
function may not change the value of const parameters.
void test1(const int num){
num = num + 1; // compile time error}
46
const Parameters in C and C++
"const" are most useful for reference, array, and pointer types.
Syntax is detailed, as shown here.
// What is constant?void test1(const int *a){ *a = *a + 1;
a = new int[100];}
int main() {int x[20];test1(x);
// What is constant?void test2(int* const b){ *b = *b + 1;
b = new int[100];}
int main() {int x[20];test2(x);
47
Limitation of const Parameters
What if a function has a "const" parameter, but passes it to another function that doesn't declare "const"?
compiler cannot verify that "const" attribute is honored
int sum( int count, const int x[ ] ) {int result = sum2(count, x);
}
// sum2 doesn't declare x as "const"int sum2( int count, int x[ ] ) {
int total = 0;while(count>0) total += x[--count]; return total;
}
48
Parameter Passing in C#
Parameters can be passed by value or reference C# uses "ref" (reference) on formal parameter type.
// C# pass by valuevoid swap(int a, int b){ int temp;
temp = a; a = b;b = temp;
}
int main() {int n = 10, m = 20;swap(n, m);/* no effect! */
// C# pass by refvoid swap(ref int a,
ref int b){ int temp;
temp = a; a = b;b = temp;
}
int main() {int n = 10, m = 20;swap(ref n, ref m);/* n, m swapped! */
49
Parameter Passing in Pascal
Pascal has both call by value is default: copy parameter to stack call by reference: specify using "var" keyword
Call by value is inefficient for large parameters
typeRealArray = array[1..10000] of real;
Procedure PassByValue( n: integer, a: RealArray ) {n and a are copies of caller's arguments
}Procedure PassByReference( var n: integer;
var a: RealArray ) {n and a are passed by reference
}
50
Array as Parameter in Pascal An array is passed by...
call by value: copy the entire array onto stack! call by reference: copy address of array onto stack.
(* pass by value: copy the ENTIRE array to stack *)procedure sumdata( x: array[1..100] of int ): int;var k, sum: int;begin
sum :=0;for k := 1 to 100 do sum := sum + x[k];return sum;
end;
(* pass by reference: copy array address to stack *)procedure sumdata( var x: array[1..100] of int ): int;
51
const Parameters in Pascal
Freepascal allows "const" parameters that cannot be assigned to (modified) inside the procedure.
Compiler will use call by value for small data (4 bytes or less), call by reference for larger parameters.
typeRealArray = array[1..1000] of real;
Procedure Invariant( const n: integer;const a: RealArray ) {n and a may not be modified heren is probably passed by valuea is always passed by reference
}
http://www.freepascal.orghttp://www.freepascal.org/docs-html/ref/ref.html
52
Parameters in C#
Default is call by value. "ref" to call by reference (like Algol). "out" for output parameters (must assign before using)
// call by referencepublic int readdata( ref int [] x ) { ... }
// call by valuepublic int sumdata( int [] x ) { ... }
// output only parameterpublic void countdata( int [] x, out int count ) {...}
53
Ada: many choices Parameters can be declared as "in", "out", or "in out" Compiler checks the usage of "in" and "out" vars. Language definition was ambiguous where "in out" is call by
reference or call by value-result.
procedure main isx, y: integer;
beginx := 10;DoubleVal( y, x );-- OK: y is 20DoubleVal( x, x );-- x still has value 10
procedure DoubleVal(a: in out integer;b: in out integer) is
-- double the value of bbegin
a := 2*b;end DoubleVal;
Is this a logic error?
54
Programming Tricks with Procedures
Inline functions Optional parameters Variable length parameter lists Templates
55
Inline Expansion C, FORTRAN, and others support inline expansion of functions: entire function code is copied into each
occurrence of function call.
Advantage: avoids overhead of function call Disadvantage: makes code larger. Not recursive.
In C, "inline" suggests that compiler use inline expansion. Compiler may ignore this request, or may "inline" functions not declared as inline.
// C example:inline double sqr(double x) { return x*x; }int main( ) {
double a, b, y;a = 10; b = 0.1;y = sqr(a - b); // sqr( ) is expanded inline
56
Inline Expansion (2)
C++ usually "inlines" constructors and functions defined inside the class.
// C++ example:class Stack {private:
int maxsize;int *top = NULL; int *stackptr;
public:// candidate for inline expansionStack(int n) {maxsize = n; stackptr = new int[n];}int pop();
}// function defined outside of class: not inlineint Stack::pop() { return *top--; }
57
Default (Optional) Parameters
Ada, C/C++, Fortran, etc., allow default parameters. Any parameters omitted from procedure call will be given
default values. Default parameters must be at the end of parameter list, to
avoid ambiguity. In C/C++ use:
// norm of a vector: can have 1 to 3 parametersdouble norm(double x, double y=0, double z=0) {
return sqrt( x*x + y*y + z*z ); }// calling sequences:r1 = norm( sin(0.5) );r2 = norm( 3.0, 4.0 );r3 = norm( 3.0, 4.0, -5.0);
58
Default Parameters: C++ example
rotate can be invoked any of these ways:
// rotate and scale point (x,y), default 90-degreesvoid rotate(double &x, double &y,
double angle=90, double scale=1.0) {angle = angle*PI/180;double xr = x*cos(angle) - y*sin(angle); double yr = x*sin(angle) + y*cos(angle);x = xr*scale;y = yr*scale;
}
rotate(x, y); // rotate 90 degreesrotate(x, y, -30.); // rotate -30 degreesrotate(x, y, 45., 0.5); // rotate 45, scale by 0.5
Useful for functions that have infrequently used options:
59
Variable Parameter Lists
C/C++ and Visual Basic have a mechanism for variable length argument lists.
Example: printf( ) and scanf( ) accept any number and type of arguments:
printf("turn %s and go %d meters", dir, distance);
printf("%8f %8f %8f", x, y, z); The first parameter (format) is used to determine
how many and what type of arguments to expect. If location of first parameter (on the stack) is known,
then remaining parameters must come after that.
60
Variable Length Parameters in C (1)
In C/C++ use varargs for variable length parameters.
// function to sum any number of values#include <stdarg.h>double sum(int n, ...){ double total = 0.0;
va_list argptr;// call va_start with address of the last known parameterva_start(argptr, &n);// Each call to va_arg returns next argument on the stack. while(n>0) {
total = total + va_arg(argptr, double);// va_arg increments argptr each time.n--;
}// va_end cleans up
va_end(argptr);return total;
}
must specify type
61
Variable Length Parameters in C (2) Why do we need to know the number of parameters?
Can varargs determine number of params itself? What happens if we read beyond the next of parameter list (call
va_arg( ) too many times)? Can we determine the type of the next argument on the stack?
// function to sum any number of values#include <stdarg.h>double sum(double x, ...) // no arg counter!!{ double total, xnext;
va_list argptr;total = x;va_start(argptr, &x);// get all parameters: this doesn't workwhile ( (xnext = va_arg(argptr, double)) != null )
total += xnext;
62
The Problem with varargs
varargs is not type safe. Compiler cannot check that argument type matches
expected data type No run-time type checking. A function can...
assign wrong data type to an argument read beyond end of arguments
Simple example:
void sub1(double a, int b, double c) {
// use wrong format -- printf will expect
// arguments to match the formats
printf("sub1: %d %f %d %ud %ud\n", a, b, c);
}
63
Variable Arguments in Java
Java 1.5 has variable arguments. Variable part must be at the end of parameter list. Type safe. Used by printf and format.
/* Better println : can print any number of objects! */
public static void println( Object ... arg ) {
// arg is an array of type Object.
// Use arg.length to determine number of args.
for(int k=0; k < arg.length; k++)
System.out.print( arg[k] );
System.out.println( ); // newline after last one
}
64
Generic Procedures and Classes
Ada and C++ provide syntax to generate a procedure or class of any type, as needed.
// generic "max" functiontemplate<typename T> // or: template<class T>T max(T a, T b) { if (a > b) return a; else return b; }
The compiler instantiates this function only when it is needed. If your code contains:
double t = 0.6; // angledouble y = max(cos(t), sin(t));
The compiler will generate and compile:
double max(double a, double b){ if (a > b) return a; else return b; }
65
Generic Classes
C++ template can define classes. Must instantiate explicitly.
template<class T, int maxsize = 100>class Stack {private:
T items[maxsize];int top;
public:Stack( ) { top = -1; } // emptyvoid push(T value) {
if (top<maxsize-1) { items[++top] = value; }else throw( StackError );
}T pop( ) { if (top>=0) return items[top--];
else throw( StackError );}...
}Stack<string, 50> stringstack; // create an object
optional template parameter
66
Vocabulary Question
Q: What do you call a family of methods which have the same name but different parameter types? I.e.
Arrays.sort( int [ ] x );
Arrays.sort( float [ ] x );
Arrays.sort( char [ ] x );
Arrays.sort( Object [ ] obj );
...
A: _______________
Q: Redefining "+" for strings: string = string1 + string2; is called operator _____________ .
67
Can an Application Detect the Parameter Passing Mechanism?
Q: What values will be printed using "pass by value", "pass by reference", and "pass by value-return"?
// What parameter passing mechanism?void CallByWhat(int& n, int& m) {
n++;if (n == m) printf("CallByWhat: identical\n");else printf("CallByWhat: not identical\n");m++;
}int main() {
int a = 0;CallByWhat( a, a);printf("main: a = %d\n", a);
}