C and generic

Source: Internet
Author: User

[Problem description] generic is a special type that delays the work of a specified type until the client Code declares and instantiates a class or method. Generics are designed to solve function name conflicts. Generic is generally considered to be the capability of advanced languages. The implementation of generic is generally based on the template concept of advanced languages. Can the C language implement generics? The answer is yes, but it is much more difficult than advanced languages. The following two generic implementation methods are summarized.

[Resolution]

Compiling environment:

Fedora 10, gcc version gcc4.3.2

1. Use function pointers to implement generics

[Code list]

Printtest. c

[Html]
# Include <stdio. h>
# Include <stdlib. h>
 
# Define DEBUG 0
 
# Define PRINTSTAT (FORMAT, STAT )\
Printf ("****************" FORMAT "Test ****************\ n "\
, STAT );
 
# Define DEBUG_PRINT (FORMAT, VALUE) printf ("File % s line % d :"\
# VALUE "=" FORMAT "\ n "\
,__ FILE __, _ LINE __, VALUE \
);
 
Enum {
RET_ OK,
RET_FAIL
};
 
Typedef int (* FXPrintFun) (void * data );
 
Int print (FXPrintFun _ print, void * data)
{
Return _ print (data );
}
 
Static int print_int (void * data)
{
Printf ("% d", (int) data );
 
Return RET_ OK;
}
 
Static int print_int2 (void * data)
{
Printf ("% d", * (int *) data );
 
Return RET_ OK;
}
 
Static int print_float (void * data)
{
Printf ("% f", * (float *) data );
 
Return RET_ OK;
}
 
Static int print_str (void * data)
{
Printf ("% s", (char *) data );
 
Return RET_ OK;
}
 
Int main (void)
{
Int I = 0;
Float f = 2.6;
Char * test = "Generics test! ";
 
Int * pi = & I;
Float * pf = & f;
 
# If DEBUG
DEBUG_PRINT ("% f", f)
# Endif
 
PRINTSTAT ("% s", "Integer ")
For (; I <10; I ++)
Print (print_int, (void *) I );
Printf ("\ n ");
 
PRINTSTAT ("% s", "Integer ")
For (I = 0; I <10; I ++)
Print (print_int2, (void *) pi );
Printf ("\ n ");
 
PRINTSTAT ("% s", "Float ")
Print (print_float, (void *) pf );
Printf ("\ n ");
 
PRINTSTAT ("% s", "String ")
Print (print_str, (void *) test );
Printf ("\ n ");
 
Return RET_ OK;
}

# Include <stdio. h>
# Include <stdlib. h>

# Define DEBUG 0

# Define PRINTSTAT (FORMAT, STAT )\
Printf ("****************" FORMAT "Test ****************\ n "\
, STAT );

# Define DEBUG_PRINT (FORMAT, VALUE) printf ("File % s line % d :"\
# VALUE "=" FORMAT "\ n "\
,__ FILE __, _ LINE __, VALUE \
);

Enum {
RET_ OK,
RET_FAIL
};

Typedef int (* FXPrintFun) (void * data );

Int print (FXPrintFun _ print, void * data)
{
Return _ print (data );
}

Static int print_int (void * data)
{
Printf ("% d", (int) data );

Return RET_ OK;
}

Static int print_int2 (void * data)
{
Printf ("% d", * (int *) data );

Return RET_ OK;
}

Static int print_float (void * data)
{
Printf ("% f", * (float *) data );

Return RET_ OK;
}

Static int print_str (void * data)
{
Printf ("% s", (char *) data );

Return RET_ OK;
}

Int main (void)
{
Int I = 0;
Float f = 2.6;
Char * test = "Generics test! ";

Int * pi = & I;
Float * pf = & f;

# If DEBUG
DEBUG_PRINT ("% f", f)
# Endif

PRINTSTAT ("% s", "Integer ")
For (; I <10; I ++)
Print (print_int, (void *) I );
Printf ("\ n ");

PRINTSTAT ("% s", "Integer ")
For (I = 0; I <10; I ++)
Print (print_int2, (void *) pi );
Printf ("\ n ");

PRINTSTAT ("% s", "Float ")
Print (print_float, (void *) pf );
Printf ("\ n ");

PRINTSTAT ("% s", "String ")
Print (print_str, (void *) test );
Printf ("\ n ");

Return RET_ OK;
}
Makefile

[Html]
OBJS = printtest. o
TARGET = printtest
SRC = printtest. c
 
All: $ (OBJS)
Gcc-g $ (OBJS)-o $ (TARGET)
$ (OBJS): printtest. s
Gcc-g-c printtest. s-o $ (OBJS)
Printtest. s: printtest. I
Gcc-g-S printtest. I-o printtest. s
Printtest. I: $ (SRC)
Gcc-g-E $ (SRC)-o printtest. I
Clean:
Rm *~ *. O *. s *. I $ (TARGET)

OBJS = printtest. o
TARGET = printtest
SRC = printtest. c

All: $ (OBJS)
Gcc-g $ (OBJS)-o $ (TARGET)
$ (OBJS): printtest. s
Gcc-g-c printtest. s-o $ (OBJS)
Printtest. s: printtest. I
Gcc-g-S printtest. I-o printtest. s
Printtest. I: $ (SRC)
Gcc-g-E $ (SRC)-o printtest. I
Clean:
Rm *~ *. O *. s *. I $ (TARGET)
* To observe the code compilation, compilation, and link processes, Makefile is slightly complicated and can be compiled directly using the following commands:

[Html] view plaincopyprint? Gcc printtest. c-o printtest

Gcc printtest. c-o printtest
 

[Running result]

[Html]
* ************** Integer Test ****************
0123456789
* ************** Integer Test ****************
0123456789
* Float Test ****************
2.600000
* ************** String Test ****************
Generics test!

* ************** Integer Test ****************
0123456789
* ************** Integer Test ****************
0123456789
* Float Test ****************
2.600000
* ************** String Test ****************
Generics test!
 


The above code is worth noting that two types of print_int functions are provided during definition:

[Html]
Static int print_int (void * data)
{
Printf ("% d", (int) data );
 
Return RET_ OK;
}
 
Static int print_int2 (void * data)
{
Printf ("% d", * (int *) data );
 
Return RET_ OK;
}

Static int print_int (void * data)
{
Printf ("% d", (int) data );

Return RET_ OK;
}

Static int print_int2 (void * data)
{
Printf ("% d", * (int *) data );

Return RET_ OK;
} Call time:

[Html]
Int I = 0;
 
Int * pi = & I;
 
PRINTSTAT ("% s", "Integer ")
For (; I <10; I ++)
Print (print_int, (void *) I );
Printf ("\ n ");
 
PRINTSTAT ("% s", "Integer ")
For (I = 0; I <10; I ++)
Print (print_int2, (void *) pi );
Printf ("\ n ");

Int I = 0;

Int * pi = & I;

PRINTSTAT ("% s", "Integer ")
For (; I <10; I ++)
Print (print_int, (void *) I );
Printf ("\ n ");

PRINTSTAT ("% s", "Integer ")
For (I = 0; I <10; I ++)
Print (print_int2, (void *) pi );
Printf ("\ n ");
When print_int is called, the int type is forcibly converted to the void * type. When print_int2 is called, the int * type is forcibly converted to the void * type. Surprisingly, both methods can output the correct results. In fact, the method provided by print_int is just a coincidence, because int Is 4 bytes, and void * is also 4 bytes, there is no error in forced conversion! However, if it is float type, it will not work if you use a method similar to print_int, and gcc prompts that conversion cannot be performed. The safe method is to convert int * to void *, convert void * to int * in the print_int processing function, and then unreference it.

 

2. Use "#"

The Code provided by method 1 shows the power. Next we will look at another Implementation of generics:

[Code list]

Printtest. h

[Html]
# Ifndef _ PRINTTEST_H __
# Define _ PRINTTEST_H __
 
# Define GNERIC_PRINT (TYPE, FORMAT, SUFFIX )\
Int print # SUFFIX (TYPE data )\
{\
Printf (FORMAT, data );\
Return 0 ;\
}
 
# Endif

# Ifndef _ PRINTTEST_H __
# Define _ PRINTTEST_H __

# Define GNERIC_PRINT (TYPE, FORMAT, SUFFIX )\
Int print # SUFFIX (TYPE data )\
{\
Printf (FORMAT, data );\
Return 0 ;\
}

# Endif

Printtest. c

[Html]
# Include <stdio. h>
# Include <stdlib. h>
# Include "printtest. h"
 
# Define DEBUG 0
 
# Define PRINTSTAT (FORMAT, STAT )\
Printf ("****************" FORMAT "Test ****************\ n "\
, STAT );
 
# Define DEBUG_PRINT (FORMAT, VALUE) printf ("File % s line % d :"\
# VALUE "=" FORMAT "\ n "\
,__ FILE __, _ LINE __, VALUE \
);
 
Enum {
RET_ OK,
RET_FAIL
};
 
GNERIC_PRINT (int, "% d", _ int)
GNERIC_PRINT (float, "% f", _ float)
GNERIC_PRINT (char *, "% s", _ str)
 
Int main (void)
{
Int I = 0;
Float f = 2.6;
Char * test = "Generics test! ";
 
# If DEBUG
DEBUG_PRINT ("% f", f)
# Endif
 
PRINTSTAT ("% s", "Integer ")
For (; I <10; I ++)
Print_int (I );
Printf ("\ n ");
 
PRINTSTAT ("% s", "Float ")
Print_float (f );
Printf ("\ n ");
 
PRINTSTAT ("% s", "String ")
Print_str (test );
Printf ("\ n ");
 
Return RET_ OK;
}

# Include <stdio. h>
# Include <stdlib. h>
# Include "printtest. h"

# Define DEBUG 0

# Define PRINTSTAT (FORMAT, STAT )\
Printf ("****************" FORMAT "Test ****************\ n "\
, STAT );

# Define DEBUG_PRINT (FORMAT, VALUE) printf ("File % s line % d :"\
# VALUE "=" FORMAT "\ n "\
,__ FILE __, _ LINE __, VALUE \
);

Enum {
RET_ OK,
RET_FAIL
};

GNERIC_PRINT (int, "% d", _ int)
GNERIC_PRINT (float, "% f", _ float)
GNERIC_PRINT (char *, "% s", _ str)

Int main (void)
{
Int I = 0;
Float f = 2.6;
Char * test = "Generics test! ";

# If DEBUG
DEBUG_PRINT ("% f", f)
# Endif

PRINTSTAT ("% s", "Integer ")
For (; I <10; I ++)
Print_int (I );
Printf ("\ n ");

PRINTSTAT ("% s", "Float ")
Print_float (f );
Printf ("\ n ");

PRINTSTAT ("% s", "String ")
Print_str (test );
Printf ("\ n ");

Return RET_ OK;
}

Makefile

[Html]
OBJS = printtest. o
TARGET = printtest
SRC = printtest. c
 
All: $ (OBJS)
Gcc-g $ (OBJS)-o $ (TARGET)
$ (OBJS): printtest. s
Gcc-g-c printtest. s-o $ (OBJS)
Printtest. s: printtest. I
Gcc-g-S printtest. I-o printtest. s
Printtest. I: $ (SRC)
Gcc-g-E $ (SRC)-o printtest. I
Clean:
Rm *~ *. O *. s *. I $ (TARGET)

OBJS = printtest. o
TARGET = printtest
SRC = printtest. c

All: $ (OBJS)
Gcc-g $ (OBJS)-o $ (TARGET)
$ (OBJS): printtest. s
Gcc-g-c printtest. s-o $ (OBJS)
Printtest. s: printtest. I
Gcc-g-S printtest. I-o printtest. s
Printtest. I: $ (SRC)
Gcc-g-E $ (SRC)-o printtest. I
Clean:
Rm *~ *. O *. s *. I $ (TARGET)
* SRC = printtest. c, instead of SRC = printtest. c printtest. h. The latter cannot properly complete preprocessing, which is confusing here. Can someone explain the reason?


Or use

[Html]
Gcc printtest. h printtest. c-o printtest

Gcc printtest. h printtest. c-o printtest
Compile

 

[Running result]

[Html]
* ************** Integer Test ****************
0123456789
* Float Test ****************
2.600000
* ************** String Test ****************
Generics test!

* ************** Integer Test ****************
0123456789
* Float Test ****************
2.600000
* ************** String Test ****************
Generics test! Www.2cto.com
 

This method seems very dazzling, but it is very prone to errors when the amount of code is huge. Therefore, we recommend that you use function pointers to implement generics.

 

Author; tandesir
 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.