1. How can "typedef" make my code portable?
The size of type int
is not exactly specified by C, it is only supposed to be at least equal to 16 bits. So, on some processor architecture, compiler implements it as 16 bits whereas on some other as 32 bits. So, if a programmer writes int a
, it would take 2 byte on the 1st architecture and 4 byte on the second -- i.e. non-uniform behavior across platforms (lack of portability considering the 'size' aspect).
To avoid that, the types are defined using names like uint_16
or uint_32
in some global header files (say, types.h). Inside types.h, the user-defined types would be correctly mapped to the suitable native type -- and there may be processor specific defines in types.h. e.g. considering your example:-
#ifdef AVR_32
typedef unsigned int uint_32
#else
typedef unsigned long uint_32
#endif
Later, a programmer would use these types(uint_16, uint_32 etc.) and won't bother about the size himself.
Typedefs in the context of portability are generally used in preprocessor macros with conditional compiling:
#if defined(INTEL_PROCESSOR)
typedef int my_desired_integer;
#elif defined(POWER_PC)
typedef long int my_desired_integer;
#elif defined(SOME_OTHER_WEIRD_PROCESSOR_OR_OS)
typedef short int my_desired_integer;
#endif
Then you use my_desired_integer
everywhere in your code and the preprocessor will make sure to put the right type into the typedef.
2. function pointer + typedef :
ref: https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work?rq=1
Function pointers in C
Let's start with a basic function which we will be pointing to:
int addInt(int n, int m) {
return n+m;
}
First thing, let's define a pointer to a function which receives 2 int
s and returns an int
:
int (*functionPtr)(int,int);
Now we can safely point to our function:
functionPtr = &addInt;
Now that we have a pointer to the function, let's use it:
int sum = (*functionPtr)(2, 3); // sum == 5
Passing the pointer to another function is basically the same:
int add2to3(int (*functionPtr)(int, int)) {
return (*functionPtr)(2, 3);
}
We can use function pointers in return values as well (try to keep up, it gets messy):
// this is a function called functionFactory which receives parameter n
// and returns a pointer to another function which receives two ints
// and it returns another int
int (*functionFactory(int n))(int, int) {
printf("Got parameter %d", n);
int (*functionPtr)(int,int) = &addInt;
return functionPtr;
}
But it's much nicer to use a typedef
:
typedef int (*myFuncDef)(int, int);
// note that the typedef name is indeed myFuncDef
myFuncDef functionFactory(int n) {
printf("Got parameter %d", n);
myFuncDef functionPtr = &addInt;
return functionPtr;
}
4. variable length argument in detail
Ref: https://blog.aaronballman.com/2012/06/how-variable-argument-lists-work-in-c/
void foo( int bar, ... ) { va_list args; va_start ( args, bar ); for (;;) { some_type t = va_arg ( args, some_type ); /* Do something with t */ } va_end ( args ); } |
typedef
unsigned
char
*
va_list
;
#define va_start(list, param) (list = (((va_list)¶m) + sizeof(param)))
#define va_arg(list, type) (*(type *)((list += sizeof(type)) - sizeof(type)))
ans 2:
If you look at the way the C language stores the parameters on the stack, the way the macros work should become clear:- Higher memory address Last parameter Penultimate parameter .... Second parameter Lower memory address First parameter StackPointer -> Return address (note, depending on the hardware the stack pointer maybe one line down and the higher and lower may be swapped) The arguments are always stored like this1, even without the ... parameter type. The va_start macro just sets up a pointer to the first function parameter, e.g.:- void func (int a, ...) { // va_start char *p = (char *) &a + sizeof a; } which makes p point to the second parameter. The va_arg macro does this:- void func (int a, ...) { // va_start char *p = (char *) &a + sizeof a; // va_arg int i1 = *((int *)p); p += sizeof (int); // va_arg int i2 = *((int *)p); p += sizeof (int); // va_arg long i2 = *((long *)p); p += sizeof (long); } The va_end macro just sets the p value to NULL.
5.typedef in detail:
https://stackoverflow.com/questions/4295432/typedef-function-pointer?rq=1
typedef is a language construct that associates a name to a type.
You use it the same way you would use the original type, for instance
typedef int myinteger;
typedef char *mystring;
typedef void (*myfunc)();
using them like
myinteger i; // is equivalent to int i;
mystring s; // is the same as char *s;
myfunc f; // compile equally as void (*f)();
As you can see, you could just replace the typedefed name with its definition given above.
The difficulty lies in the pointer to functions syntax and readability in C and C++, and the typedef
can improve the readability of such declarations. However, the syntax is appropriate, since functions -
unlike other simpler types - may have a return value and parameters, thus the sometimes lengthy and
complex declaration of a pointer to function.
The readability may start to be really tricky with pointers to functions arrays, and some other even more indirect flavors.
To answer your three questions
Why is typedef used? To ease the reading of the code - especially for pointers to functions, or structure names.
The syntax looks odd (in the pointer to function declaration) That syntax is not obvious to read, at least when beginning.
Using a typedef declaration instead eases the reading
Is a function pointer created to store the memory address of a function? Yes, a function pointer stores the address of a function.
This has nothing to do with the typedef construct which only ease the writing/reading of a program ; the compiler just expands the
typedef definition before compiling the actual code.
#include <stdio.h>
#include <math.h>
/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/
// typedef a primitive data type
typedef double distance;
// typedef struct
typedef struct{
int x;
int y;
} point;
//typedef an array
typedef point points[100];
points ps = {0}; // ps is an array of 100 point
// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)
// prototype a function
distance findDistance(point, point);
int main(int argc, char const *argv[])
{
// delcare a function pointer
distanceFun_p func_p;
// initialize the function pointer with a function address
func_p = findDistance;
// initialize two point variables
point p1 = {0,0} , p2 = {1,1};
// call the function through the pointer
distance d = func_p(p1,p2);
printf("the distance is %f\n", d );
return 0;
}
distance findDistance(point p1, point p2)
{
distance xdiff = p1.x - p2.x;
distance ydiff = p1.y - p2.y;
return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
}
No comments:
Post a Comment