introduction to c and cmex e177 april 1, 2008 pack/e177 copyright 2005-8, andy packard. this work is...

27
Introduction to C and CMex E177 April 1, 2008 http://jagger.me.berkeley.edu/~pack /e177 Copyright 2005-8, Andy Packard. This work is licensed under the Creative Commons Attribution-ShareAlike License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

Upload: joanna-fox

Post on 17-Jan-2016

215 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Introduction to C and CMexE177

April 1, 2008http://jagger.me.berkeley.edu/~pack/e177

Copyright 2005-8, Andy Packard. This work is licensed under the Creative Commons Attribution-ShareAlike License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.

Page 2: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Variables and Addressesint B=7;double A=3.2, D;double *P; /* addressofdouble P */

Name Address Contents@Address (ie. value of variable)B 0xFA12 7A 0xFA32 3.2D 0xFA4A garbageP 0xFA70 garbage

P = &A;

Name Address Contents@AddressB 0xFA12 7A 0xFA32 3.2D 0xFA4A garbageP 0xFA70 0xFA32

*P = 4.71; D = 13.9;

Name Address Contents@AddressB 0xFA12 7A 0xFA32 4.71D 0xFA4A 13.9P 0xFA70 0xFA32

P = &D;

Name Address Contents@AddressB 0xFA12 7A 0xFA32 4.71D 0xFA4A 13.9P 0xFA70 0xFA4A

Page 3: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

A simple program (simple1.c)This program illustrates the double and pointer variable types, address operator (&), the dereference operator (*) and the printf output function.

#include <stdio.h>int main(void){int b;double a;double *p; /* Defines a variable p */ /* The variable p can hold the address of a DOUBLE */ /* This does not declare a DOUBLE */a = 1.3;b = -6;printf(" The value of a and b are %g, %d\n",a,b); printf("The addresses of a and b are %p, %p\n",&a,&b); p = &a; /* & is address operator */printf(" The value of p is %p\n",p); printf(" The address of p is %p\n",&p); printf(" The value that p points to is %g\n",*p); a = 2.3;printf(" The value of a is %g, the address is %p\n",a,&a); printf(" The value that p points to is %g\n",*p);return(0);}

addressOfdouble p;

Format specifiers

Variable declarations

Assign the value of p to be the address of a

Change the value of the variable a. Remember

that p still contains the address of a

Dereference operator: *p is the value at memory address stored in p

Page 4: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Another simple program (array1.c) This program illustrates arrays, the increment operator (++), and for loops

#include <stdio.h>int main(void){double A[3];int i; A[0] = 1.2;A[1] = 1.21;A[2] = 1.22; printf(" The value of A is %p\n",A); for (i=0;i<=2;i++) { printf("i=%d\n",i); printf("The value of A[%d] is %g\n",i,A[i]); printf("The value of *(A+%d) is %g\n",i,*(A+i)); printf("The value of A+%d is %p\n",i,A+i); printf("The address of A[%d] is %p\n",i,&(A[i])); }return(0);}

Declare A to be an array of 3 doubles

Assign values to the elements of A

By definition, the “value” of the array, by itself, is the address of its first element.

Page 5: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

The for loop The for loop from the previous slide

int i;

for (i=0; i<=2; i++) {

printf("i=%d\n",i);

printf("The value of A[%d] is %g\n",i,A[i]);

printf("The value of *(A+%d) is %g\n",i,*(A+i));

printf("The value of A+%d is %p\n",i,A+i);

printf("The address of A[%d] is %p\n",i,&(A[i]));

}

Initialization, done once before the loop is

entered

TEST: if TRUE, body is executed. Loop terminates when

condition is false Executed after Body is executed (almost always an increment of some sort)

repeat

Start of BODY

End of BODY

Page 6: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

#include <stdio.h>int main(void){double *X;int i, N=3, *Y; X = (double *) calloc(N, sizeof(double));*X = 1.2;*(X+1) = 1.21;*(X+2) = 1.22;Y = (int *) calloc(N, sizeof(int)); printf("The address of X is %p\n",&X); printf(" The value of X is %p\n",X); printf(" The value of *X is %g\n",*X); for (i=0;i<2;i++) { printf("i=%d\n",i); printf("The value of X[%d] is %g\n",i,X[i]); printf("The value of *(X+%d) is %g\n",i,*(X+i)); printf("The value of X+%d is %p\n",i,X+i); printf("The value of Y+%d is %p\n",i,Y+i); printf("The address of X[%d] is %p\n",i,&(X[i])); }free(X);free(Y);return(0);}

Dynamic Memory Allocation (allocate1.c)In this program, memory is allocated while the program runs, not just in variable declarations

Allocate memory to hold N elements whose size is the

same as DOUBLEs

Assign values at the addresses X, X+1 and X+2.

Allocate memory to hold N INTs

Free memory that was dynamically allocated but

no longer used.

Returned value (X) is the address of the beginning of the allocated memory

Page 7: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

#include <stdio.h>int sub1(int arg1, int *arg2); int main(void){int A=2, B=6, C;printf("Before Call\n");printf(" A = %d, A_Address = %p.\n", A, &A);printf(" B = %d, B_Address = %p.\n", B, &B);printf(" C = %d, C_Address = %p.\n", C, &C);C = sub1(A,&B);printf("After Call\n");printf(" A = %d, A_Address = %p.\n", A, &A);printf(" B = %d, B_Address = %p.\n", B, &B);printf(" C = %d, C_Address = %p.\n", C, &C);return(C);}

Functions (subroutines1.c) Function calls pass arguments by value (a copy is passed into subroutine)

int sub1(int a1, int *a2){printf(" IN SUB1, BEFORE calculation.\n");printf(" a1=%d, address=%p.\n", a1, &a1);printf(" a2=%p, address=%p.\n", a2, &a2);a1 = a1 + 1;*a2 = *a2 + 3;printf(" IN SUB1, AFTER calculation.\n");printf(" a1=%d, address=%p.\n", a1, &a1);printf(" a2=%p, address=%p.\n", a2, &a2);return(a1+*a2);}

Subroutines pass arguments by their value (ie., a copy). If you want to

change the input arguments, don’t pass the variables, pass their addresses.

Similarly, if the variable takes up a lot of memory, pass its address (small)

Page 8: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

#include <stdio.h>void sub2(int arg1[]); int main(void){int A[2];A[0] = 2.0; A[1] = 4.0;printf("Before Call\n");printf(" A[0] = %d\n", A[0]);printf(" A[1] = %d\n", A[1]);printf(" A = %p\n", A);sub2(A);printf("After Call\n");printf(" A[0] = %d\n", A[0]);printf(" A[1] = %d\n", A[1]);printf(" A = %p\n", A);return(0);}

Functions (subroutines2.c) Function calls pass arguments by value (a copy is passed into subroutine). Recall that the “value” of an array is the address of its 1st element.

void sub2(int a1[]){printf(" IN SUB2, BEFORE calculation.\n");printf(" a1=%p\n",a1);printf(" a1[0]=%d\n",a1[0]);printf(" a1[1]=%d\n",a1[1]);a1[0] = a1[0] + a1[1];printf(" IN SUB2, AFTER calculation.\n");printf(" a1=%p\n",a1);printf(" a1[0]=%d\n",a1[0]);printf(" a1[1]=%d\n",a1[1]);}

Subroutines pass arguments by their value (ie., a copy). The “value” of an array is the address of its first element. So, passing an array to a

subroutine still allows for the subroutine to change the contents of

the array.

Page 9: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Matlab variable types: primitives

The three main object classes in Matlab are– double

• multidimensional array of double precision floating point numbers

– char• multidimensional array of ascii characters

– logical• Multidimensional array of 1-bit (0/1) numbers

Eight other built-in primitive variable types are– uint8, uint16, uint32, uint64

• multidimensional array of 8, 16, 32 or 64-bit, unsigned integers

– int8, int16, int32, int64• multidimensional array of 8, 16, 32 or 64-bit, signed integers

Two things to rememberEvery variable in Matlab is an array

Arrays are at least 2-dimensional (no notion of 1-d array)

Recall, from Lecture #1

and...

Page 10: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Matlab variable types: derived primitives

Two other important object classes in Matlab are– cell

• multidimensional array of “containers”

– struct• multidimensional array of a structure with fields (common across array)

In a cell, the contents of a container may be– double, char, intXX, uintYY– Another cell array

– A struct array

– An object of other classes (listed on next slide)

In a struct, the value of a field may be– Same list as above

Managed arrays of pointers to Matlab variables

also, from Lecture #1

Page 11: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

mxArray *pMat;

... /* code to put a legal address in pMat */

if (mxIsComplex(pMat)) { /* code here */ };

else if (mxIsCell(pMat)) { /* code here */ };

else if (mxIsStruct(pMat)) { /* code here */ };

The mxArray object

Inside the C-programs we interface to Matlab, these types of objects will always be variables of the type mxArray.

We will never usually have an mxArray variable, but will always have pointers to them. The mxZZZZ routines have input arguments that are addresses of mxArray variables.

Typical example within a CMex file pMat can hold the address of an mxArray

TRUE if pMat points to a struct, FALSE otherwise.

Page 12: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Structures in CDeclaring a structure in C involves tagging/identifying its type, and listing the fields. For example, we might declare structures of type matrix as

struct matrix

{

char *name; /* address to first character */

int ndims; /* number of dimensions */

int *dims; /* address to dimensions */

double *addRealPart; /* address to real part */

double *addImagPart; /* address to imag part */

};

int D;

struct matrix A, B, *C;

A.addRealPart = (double *) calloc(10, sizeof(double));

C = &A; (*C).ndims = 3; C->ndims = 3;

Defines A, B to be variables of type struct matrix. Defines C to be variable whose

value can be the address of a struct matrix

Defines a new variable type, the type is struct matrix

Defines D to be variables of type int

Page 13: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

The mexFunction gatewaySuppose we have a file somefunction.c

What happens if in Matlab (ie, at command line, in script, or in function) a command of the form

[Y,Z] = somefunction(A,B,C);

is executed?

#include "mex.h"

void mexFunction(int nLHS, mxArray *pLHS[],

int nRHS, const mxArray *pRHS[])

{

/* Code here */

}

somefunction.c

Page 14: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

The mexFunction gateway (cont’d)somefunction.c looks like

The function definition says–mexFunction returns nothing (void)–mexFunction accepts 4 arguments

• 1st argument in an integer

• 2nd argument is an array of (pointers to mxArray)• 3rd argument is an integer

• 4th argument is an array of (pointers to mxArray), moreover, the value of this variable will not be changed (const qualifier)

#include "mex.h"

void mexFunction(int nLHS,

mxArray *pLHS[],

int nRHS,

const mxArray *pRHS[])

{ /* Code here */ }

somefunction.c

Remember, in C, the arrayname, by itself, is actually the address of the first element. So, by

changing the array elements in the subroutine, you are really changing the array elements back in the

calling routine as well... See subroutines2.c example.

In this case, the elements of the array pLHS (which are

addresses of mxArray objects) will be changed.

Page 15: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

The mexFunction gateway

Before executing

[Y,Z] = somefunction(A,B,C);

we first need to compile the function. At the Matlab prompt, execute the command

>> mex somefunction.c

This will create an executable file in the same folder that can be called directly from Matlab.

You may have to (once) set up the MEX infrastructure if you haven’t already. In that case, type

>> mex –setup

and simply follow the instructions.

Page 16: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

The mexFunction gateway

Suppose variables A, B and C exist in the current workspace. Executing [Y,Z] = somefunction(A,B,C)will call the compiled code (function declaration shown below)

Upon entry–nRHS will equal 3–pRHS[0] will be the address of mxArray A–pRHS[1] will be the address of mxArray B–pRHS[2] will be the address of mxArray C–nLHS will equal 2–pLHS[0] can hold the address of an mxArray–pLHS[1] can hold the address of an mxArray

void mexFunction(int nLHS, mxArray *pLHS[],

int nRHS, const mxArray *pRHS[])

mexFunction Code needs to• create 2 mxArrays• fill them in with results, and• put their addresses in pLHS

somefunction.c

Page 17: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Where is raw data stored in double arrays

If pMAT is a pointer to an mxArray, and

mxIsDouble(pMat)

is TRUE, then–mxGetPr returns the address of the first element of the real part

(stored in linear order)–mxGetPi returns the address of the first element of the imaginary part

double *pReal, *pImag;

mxArray *pMat;

/* code to put a legal address in pMat */

pReal = mxGetPr(pMat);

if (mxIsComplex(pMat)) {

pImag = mxGetPi(pMat);

}

Page 18: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Where are the contents of cell arrays

If pCell is a pointer to an mxArray, and mxIsCell(pCell)is TRUE, then with integer J≥0,–mxGetCell(pCell,J) returns the address of the (J+1)th mxArray

in the cell (using linear ordering)

Let’s use this to study addresses in cells, in pdisplay.c

int idx;

mxArray *pMat, *pCell;

...

idx = 0; /* the first element */

pMat = mxGetCell(pCell,idx);

idx = 1;

pMat = mxGetCell(pCell,idx); /* 2nd elmnt */

cell is basically an array of pointers to mxArray objects

Page 19: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

mxZZZ and mexZZZ utilities in pdisplay.c

mxIsCellmexPrintfmxGetNumberOfDimensionsmxGetMmxGetNmxIsDoublemxIsStruct

mexErrMsgTxt

Page 20: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

mxCreate utilities

A few special mx-utilities to create a scalar mxArray–mxCreateDoubleScalar creates a 1-by-1 double –mxCreateLogicalScalar creates a 1-by-1 logical

Several mx-utilities create a 2-D mxArray–mxCreateDoubleMatrix creates a 2-d double –mxCreateCellMatrix creates a 2-d cell–mxCreateStructMatrix creates a 2-d struct–mxCreateString creates a 1-by-N char array

Several mx-utilities to create an N-D mxArray–mxCreateDoubleArray creates an N-D double–mxCreateCellArray creates an N-D cell–mxCreateStructArray creates an N-D struct–mxCreateCharArray creates an N-D char

Page 21: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

mxCreate utilities

The mxCreate utilities return a pointer to an mxArray.

This is one way to create output arguments. Recall for the mex gateway,

–pLHS[0] can hold the address of an mxArray–pLHS[1] can hold the address of an mxArray–...

mxArray *pArray, *pArray2;

...

pArray = mxCreateDoubleScalar(4.3);

pArray2 = mxCreateString("A string");

void mexFunction(int nLHS, mxArray *pLHS[],

int nRHS, const mxArray *pRHS[])

mexFunction Code needs to• create mxArrays• fill them in with results, and• put their addresses in pLHS

Page 22: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

mxCreate utilities

Here is a simple program that returns two arguments.

>> [a,b] = createTwo;

#include "mex.h"void mexFunction(int nLHS, mxArray *pLHS[], int nRHS, const mxArray *pRHS[]){ if (nLHS==2 && nRHS==0) { pLHS[0] = mxCreateString("This is a string"); pLHS[1] = mxCreateDoubleScalar(11.8); } else { mexErrMsgTxt("Must be: 2 outputs, no inputs."); }}

createTwo.c

Page 23: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Example Vector Cross Product

Let A and B be 3-by-1 column vectors, representing the Cartesian components of vectors.

The cross-product of A and B, denoted A×B, is also a vector, whose 3 components are given by

1221

3113

2332

BA-BA

BA-BA

BA-BA

BA

function C = cross177m(A,B)C = zeros(3,1);C(1) = A(2)*B(3) – A(3)*B(2);C(2) = A(3)*B(1) – A(1)*B(3);C(3) = A(1)*B(2) – A(2)*B(1);

cross177m.m

Need some error checking too...

Page 24: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Vector Cross Product : CMex function C = cross177m(A,B)C = zeros(3,1);C(1) = A(2)*B(3) – A(3)*B(2);C(2) = A(3)*B(1) – A(1)*B(3);C(3) = A(1)*B(2) – A(2)*B(1);

cross177m.m

#include "mex.h"void mexFunction(int nLHS, mxArray *pLHS[], int nRHS, const mxArray *pRHS[]){ double *pA, *pB, *pC; pLHS[0] = mxCreateDoubleMatrix(3,1,mxREAL); pC = mxGetPr(pLHS[0]); /* 3-by-1 answer starts here */ pA = mxGetPr(pRHS[0]); /* pointer to data in A */ pB = mxGetPr(pRHS[1]); /* pointer to data in B */ pC[0] = pA[1]*pB[2] - pA[2]*pB[1]; pC[1] = pA[2]*pB[0] - pA[0]*pB[2]; pC[2] = pA[0]*pB[1] - pA[1]*pB[0];}

cross177c.c

Need some error checking too...

Page 25: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

CMex with Error Checkingvoid mexFunction(int nLHS, mxArray *pLHS[], int nRHS, const mxArray *pRHS[]){ double *pA, *pB, *pC; /* Number of Arguments */ if (nLHS==1 && nRHS==2) { /* Both input arguments are DOUBLEs */ if (mxIsDouble(pRHS[0]) && mxIsDouble(pRHS[1])) { /* Both input arguments are REAL */ if (~mxIsComplex(pRHS[0]) && ~mxIsComplex(pRHS[1])) { /* 1st input argument should be 2-d */ if (mxGetNumberOfDimensions(pRHS[0])==2) { /* 2nd input argument should be 2-d */ if (mxGetNumberOfDimensions(pRHS[1])==2) { /* Both input arguments need 3 rows */ if (mxGetM(pRHS[0])==3 && mxGetM(pRHS[1])==3) { /* Both input arguments need 1 column */ if (mxGetN(pRHS[0])==1 && mxGetN(pRHS[1])==1) {

cross177cAll.c

Page 26: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Calling Matlab functions in CMex file

Follow the mexFunction gateway syntax–Declare two arrays that hold addresses of mxArrays–Fill one array with addresses of mxArray (the input arguments)–Call mexCallMATLAB, passing it 5 arguments

•Number of output arguments•(unfilled) array to hold output argument addresses•Number of input arguments•(filled) array holding the input argument addresses•Matlab function name

mxArray *localIN[4], *localOUT[3];int rval; localIN[0] = ...;...localIN[3] = ...; rval = mexCallMATLAB(3,localOUT,4,localIN,"fname");

Page 27: Introduction to C and CMex E177 April 1, 2008 pack/e177 Copyright 2005-8, Andy Packard. This work is licensed under the

Calling Matlab functions in CMex file#include "mex.h"void mexFunction(int nLHS, mxArray *pLHS[], int nRHS, const mxArray *pRHS[]){ mxArray *localIN[1], *localOUT[2]; int rval; localIN[0] = pRHS[0]; rval = mexCallMATLAB(2,localOUT,1,localIN,"eig"); pLHS[0] = localOUT[1]; mxDestroyArray(localOUT[0]);}

callEig.c

Destroy unused mxArrays