<<

typedef: Primitives typedef primitive equiv1 [, equiv2, equiv3...]; equiv [,eqiv2, eqiv3] are synonyms for primitive typedef primitive *pequiv; pequiv is a synonym for pointer‐to primitive

Examples: typedef unsigned char BYTE_t; typedef unsigned char *BYTE_p_t; typedef int PERSON_ID_t, OFFICE_ID_t, *OFFICE_ID_p_t; typedef: structs typedef struct tag { ... } equiv1 [, equiv2, equiv3...]; equiv [,eqiv2, eqiv3] are synonyms for struct tag typedef struct tag { ... } *pequiv; pequiv is a synonym for pointer‐to struct tag

Example: typedef struct DIM_t tag is { optional double width; double height; } DIM_t, *DIM_p_t; typedef: renaming types typedef typedef-name equiv1 [, equiv2, equiv3...]; equiv [,eqiv2, eqiv3] are synonyms for typedef-name typedef typedef-name *pequiv; pequiv is a synonym for pointer‐to typedef-name

Examples: typedef DIM_t RECT_t, *RECT_p_t, ELLIPSE_t, *ELLIPSE_p_t; typedef: arrays typedef type equiv[n]; equiv is a synonym for type[n]

Example: typedef struct point_s { double xco; double yco; } POINT_t;

typedef POINT_t CORNORS_t[4]; typedef: functions typedef type equiv( type1 param1 [, type2 param2, ...] ); equiv is a synonym for function returning type having parameters type1 param1 [, type2 param2, ...] typedef type (*equiv)( type1 param1 [, type2 param2, ...] ); equiv is a synonym for pointer‐to function returning type having parameters type1 param1 [, type2 param2, ...]

Examples: typedef void FUNK_t( int size, int *array ); typedef void (*FUNK_p_t)( int size, int *array ); typedef: Forward References typedef struct tag *equiv; equiv is a synonym for pointer to incomplete type struct tag.

Example: typedef struct event_s *EVENT_p_t; typedef struct event_s { EVENT_p_t nextEvent; unsigned long milliseconds; } EVENT_t; Exercises

1. Copy the POINT_t and CORNOR_t declarations from the slides. Write a declaration, CORNOR_t cornor = { . . . }, that initializes corner to coordinates{{10, 20}, {30, 20}, {10, 40}, {20, 40}}. Write a for loop that prints each pair of coordinates on a separate line. 2. Declare two structs, Test1 and Test2, in which Test1 contains a pointer to Test2, and Test2 contains a pointer to Test1. Use forward references to resolve dependencies. 3. Write three functions, each with return type void and one int parameter, which is printed to stdout. Write typedef equivalences for this type of function, and pointer‐to this type of function; use one of the equivalences to declare prototypes for the three functions. Write a typedef equivalence of type array‐of‐3 pointers‐to this type of function. Use the last typedef equivalence to create an array variable, and initialize it to the addresses of the three functions. Write a for loop to call each function in the array. enum: Declaration enum tag { ec1 [, ec2, ec3 ... ]}; ec1 [, ec2, ec3 ... ] are enumerated constants of type int, sequentially assigned values starting from 0.

Example: enum color_e { Output: 0, 1, 2 YELLOW, GREEN, PINK }; enum color_e background = PINK; printf( "%, %d, %d\n", YELLOW, GREEN, background ); enum: typedef equivalences

Example: typedef enum color_e { YELLOW, GREEN, PINK } COLOR_e_t;

COLOR_t background = PINK; enum: Initial Constant Values enum days_e { EC0, EC1, EC2, EC3 = -20, EC4 = -10, EC5, Output: EC6 0, 1, 2, ‐20, ‐10, ‐9, ‐8 } DAYS_t;

printf( "%d, %d, %d, %d, %d, %d, %d\n", EC0, EC1, EC2, EC3, EC4, EC5, EC6 ); enum: Weak Typing

Enumerated constants are not strongly‐typed. Example: enum color_e enum color_e color = SUCCESS; { enum status_e status = PINK; YELLOW, int inx = FAILURE; GREEN, PINK }; enum status_e { SUCCESS, FAILURE }; Exercise

1. Use typedef to create an , DAYS_e_t, whose constant values are named after the days of the week. 2. Write the function static const char *dayAsString( DAYS_e_t day ) which returns a string that identifies the name of the given day. 3. Write a program to test your work. Function Pointers: Function Types

The type of a function is the type of value it returns in conjunction with the number and type of its parameters.

/* Function type: * function having int, char* and * double parameters and * returning type unsigned int. */ unsigned funk( int, char*, double ); Function Pointers: Function Return Types

The return type of a function may be anything except: array; and function (A function may return a pointer to an array or a pointer to a function.)

typedef unsigned FUNC_TYPE_t( int, char*, double ); typedef FUNC_TYPE_t *FUNC_TYPE_p_t;

int[4] funk1( void ); /* NOT ALLOWED: returning array */ int *funk2( void ); /* ALLOWED: returning pointer to array */ FUNC_TYPE_t funk3( void ); /* NOT ALLOWED: returning function */ FUNC_TYPE_p_t funk4( void ); /* ALLOWED: returning pointer to function */ Function Pointers: Function Addresses

The name of a function may be assigned to a pointer of the appropriate type, in which case the function name is converted to the address of the function.

int funkE( int, const char*, double ); int (*fp1)( int, const char*, double ) = funkE; /* ALLOWED */ int (*fp2)( const char*, double ) = funkE; /* NOT ALLOWED */ char *fp3 = funkE; /* NOT ALLOWED */ Function Pointers: Function Addresses (cont’d)

The name of a function may be used as an argument to another function provided its type matches the type of the corresponding function parameter; in this case the name of the function is converted to the address of the function.

int funkE( int parm1, int (*parm2)( int, const char*, double ) ); int funkF( int, const char*, double ); void funkG( int, const char*, double ); int inx = funkE( 5, funkF ); /* ALLOWED */ int jnx = funkE( 5, funkG ); /* NOT ALLOWED */ Function Pointers: Illegal Operations • The name of a function may not be used as the operand of the sizeof operator. • The address of a function may not be converted to a void pointer. int funkE( int, const char*, double ); size_t inx = sizeof(funkE); /* NOT ALLOWED */ void *ptr = funkE; /* NOT ALLOWED */ Interpreting Declarations: the Right to Left Rule

1. Find the identifier. 2. Move to the right identifying operators and types until you hit a right parenthesis, an equal sign, or the end of the expression. (Note: a left parenthesis at this point denotes the start of the function operator; the matching right parenthesis is the end of the function operator, not a stopping point.) 3. Move to the left of the identifier, interpreting types and operators until you hit the beginning of the expression, or a left parenthesis. 4. Continue to the right where you left off. The Right to Left Rule: Example 1 int inx = 0;

inx is... an int int *pinx = NULL;

pinx is... an pointer to ... an int The Right to Left Rule: Example 2 int funk( void );

funk is... a function with no parameters... returning int int (*funk)( void );

funk is... a pointer... to a function with no parameters... returning int Function Pointers: Characteristics

• Usually point to a block of memory containing information about how to invoke a function. • May not be used in pointer arithmetic. • May be a differ in size from other pointer types. Function Pointers: Example, Page 1

typedef int TEST_PROC_t( void ); typedef TEST_PROC_t *TEST_PROC_p_t; typedef struct test_desc_s { const char *description; TEST_PROC_p_t proc; } TEST_DESC_t, *TEST_DESC_p_t;

static TEST_PROC_t test01; static TEST_PROC_t test02; static TEST_PROC_t test03;

static TEST_DESC_t all_tests_[] = { { "This is test #1", test01 }, { "This is test #2", test02 }, { "This is test #3", test03 } }; static num_tests_ = sizeof(all_tests_)/sizeof(*all_tests_); Function Pointers: Example, Page 2

int main( int argc, char **argv ) { int result = EXIT_SUCCESS; TEST_DESC_p_t test = all_tests_; int inx = 0;

for ( inx = 0 ; inx < num_tests_ && result == EXIT_SUCCESS ; ++inx ) { printf( "%s... ", test[inx].description ); if ( test[inx].proc() ) printf( "SUCCESS\n" ); else { printf( "FAILURE\n" ); result = EXIT_FAILURE; } } return result; } Exercise Function Pointers: Example, Page 3

static int test01( void ) { return 1; }

static int test02( void ) { return 1; }

static int test03( void ) { return 1; } Function Pointers: Returning

static void log_stderr( const char *, ... ); static void log_syslog( const char *, ... ); static void (*set_log( int argc, char **argv ))( const char *, ... ) { void (*log)( const char*, ... ) = log_syslog; if ( argc > 1 && strcmp( argv[1], "-debug" ) == 0 ) log = log_stderr;

return log; } int main( int argc, char **argv ) { int result = EXIT_SUCCESS; void (*log)( const char*, ... ) = set_log( argc, argv ); funk1( log ); . . . return result; } Function Pointers: Returning (alternative)

typedef void LOG_PROC_t( const char *, ... ); typedef LOG_PROC_t *LOG_PROC_p_t;

static LOG_PROC_t log_stderr; static LOG_PROC_t log_syslog;

static LOG_PROC_p_t set_log( int argc, char **argv ) { LOG_PROC_p_t log = log_syslog; if ( argc > 1 && strcmp( argv[1], "-debug" ) == 0 ) log = log_stderr;

return log; } int main( int argc, char **argv ) { int result = EXIT_SUCCESS; void (*log)( const char*, ... ) = set_log( argc, argv ); //funk1( log ); return result; } Exercise

1. Declare STATE_PROC_t to be type function with no parameters returning bool. 2. Declare STATE_PROC_p_t to be type pointer to STATE_PROC_t. 3. Declare stateProc1, stateProc2, stateProc3 and stateProc4 to be type STATE_PROC_t. 4. Create an array of type STATE_PROC_p_t and initialize it to the addresses of stateProc1, stateProc2, stateProc3 and stateProc4. 5. Declare global variable static int state = 0. 6. Write the function static bool nextProc( void )that calls the next state‐ proc from the STATE_PROC_p_t array, and returns the value obtained from the state‐proc.