Thread: Conversion of pointers to functions

  1. #1
    Registered User
    Join Date
    Jul 2005
    Posts
    98

    Conversion of pointers to functions

    References to section numbers are to the C99 standard as found at http://www.open-std.org/JTC1/SC22/WG...docs/n1124.pdf.

    Item 3 of Sec 6.5.4 "Cast operators" says: "Conversion that involve pointers, other than when permitted by the constraints of 6.5.16.1, shall be specified by means of an explicit cast."
    Item 1 of Sec 6.5.16.1 "Simple Assignment" says: "One of the following shall hold: both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right."
    A function type is really a type of pointer to function. So, if one function is a left operand of a simple assignment and the another function is the right operand, no casting (of the right operand) is needed, as long as both operands are of compatible types.
    Item 20 of Sec 6.2.5 "Types" says: "A function type describes a function with specified return type. ... A function type is said to be derived from its return type ..." This seems to suggest that as long as the return type is the same, two functions have the SAME type. In other words, int f1(void *, float, ...) and int f2(int) would have the SAME type, because both return an int; their parameters don't matter. On the other hand, Item 1 of Sec 6.2.7 "Types" says "Two types have compatible types if their types are the same." It appears they simply wish to define 'COMPATIBLE type' as a synonym of 'SAME type'. (Why don't they just say 'SAME type'?!) Item 15 of Sec 6.7.5.3 says: "For two function types to be compatible, both shall specify compatible return types." Well, OK, what they seem to be trying to say is: In respect of two functions, 1. if their return types are the same, they are of the same types, and therefore they have compatible type, 2. if their return types are not the same, but just compatible, then they still have compatible type.
    Footnote 138 at Sec 6.9.1 on page 141 specifically says
    "int g() {}" has type compatible with F which is:
    "typedef int F(void);" I guess this is by the first criteria: F and g have the SAME type.
    Now, going back to the simple assignment, if both the LHS and the RHS operands are of compatible type, no casting is needed.

    The last bullet of Sec 6.3.2.3 "Conversion - Pointers" says: "A pointer to function of one type may be converted to a pointer of another type and back again; the result shall compare equal to the original pointer." So, one function can be implicitly converted, without casting, to another (if they have compatible type), or can be explicitly converted, with casting, to another (if they do not have compatible type).


    Here are five variants of a program:
    Code:
    // Program #1
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef int t_c_function();
    typedef t_c_function *p_c_function;
    
    int g(void *x, ...)
    { return 1; }
    
    int main()
    {
     int i = 0;
     p_c_function *functions = malloc(1000);
     *functions = (int (*)())g;
     i = (*functions)(NULL);
     printf("%d\n", i);
    }
    Code:
    // Program #2
    typedef int t_c_function();
    typedef t_c_function *p_c_function;
    
    int g(void *x, ...)
    { return 1; }
    
    int main()
    {
     int i = 0;
     p_c_function *functions = malloc(1000);
     *functions = g;
     i = (*functions)(NULL);
     printf("%d\n", i);
    }
    Code:
    // Program #3
    typedef int t_c_function(void *);
    typedef t_c_function *p_c_function;
    
    int g(void *x, ...)
    { return 1; }
    
    int main()
    {
     int i = 0;
     p_c_function *functions = malloc(1000);
     *functions = (int (*)())g; 
     i = (*functions)(NULL);
     printf("%d\n", i);
    }
    Code:
    // Program #4
    typedef int t_c_function(void *);
    typedef t_c_function *p_c_function;
    
    int g(void *x, ...)
    { return 1; }
    
    int main()
    {
     int i = 0;
     p_c_function *functions = malloc(1000);
     *functions = g; 
     i = (*functions)(NULL);
     printf("%d\n", i);
    }
    Code:
    // Program #5
    typedef int t_c_function(void *);
    typedef t_c_function *p_c_function;
    
    int g(void *x, ...)
    { return 1; }
    
    int main()
    {
     int i = 0;
     p_c_function *functions = malloc(1000);
     *functions = g; 
     i = ((int (*)(void *, ...))(*functions))(NULL);
     printf("%d\n", i);
    }
    The results of the compilation and execution of the programs are:
    Code:
    rupert% uname -a
    Linux rupert 2.6.18-92.1.22.el5 #1 SMP Tue Dec 16 11:57:43 EST 2008 x86_64 x86_64 x86_64 GNU/Linux
    rupert % gcc --version
    gcc (GCC) 4.1.2 20071124 (Red Hat 4.1.2-42)
    
    rupert % gcc -o prog1 prog1.c
    rupert % prog1
    1
    
    rupert % gcc -o prog2 prog2.c
    prog2.c: In function 'main':
    prog2.c:22: warning: assignment from incompatible pointer type
    rupert % prog2
    1
    
    rupert % gcc -o prog3 prog3.c
    rupert % prog3
    Illegal instruction (core dumped)
    
    rupert % gcc -o prog4 prog4.c
    prog4.c: In function 'main':
    prog4.c:22: warning: assignment from incompatible pointer type
    rupert % prog4
    Illegal instruction (core dumped)
    
    rupert % gcc -o prog5 prog5.c
    rupert % prog5
    1
    So, when a function is called with its parameter, it must be somehow converted back to a type declared in its declaration? If Program 1 is OK, shouldn't Program 3 be OK too? Alternatively speaking, should Program 1 have failed too, for the sake of consistency? When the function g is "deferenced" from *functions and put in the RHS of the assignment statement, called with the NULL argument, can it be viewed as an implicit conversion where no casting is needed?
    With the following compiler and platform, I can compile and execute Programs 3 and 4 getting the output of 1:
    Code:
    hermod0 % uname -a
    Linux hermod0 2.6.22-gentoo-r18 #1 SMP Mon Feb 11 10:42:53 PST 2008 i686 Intel(R) Pentium(R) 4 CPU 3.00GHz GenuineIntel GNU/Linux
    hermod0 % gcc --version
    gcc (GCC) 3.4.4
    It seems
    int t_c_function();
    that is, a declaration with an empty parameter list, is the most flexible. One can put in any function in its place as long as the function returns int. So, one can put in
    int h(void *);
    or
    int h(float, float);
    for example. But Sec 6.11.6 says "Function declarators: The use of function declarators with empty parenthesis (not prototype-format parameter type declarators) is an obsolete feature."
    Is there something that is not obsolete and is as flexible?
    Last edited by hzmonte; 01-20-2009 at 02:57 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Passing Structure Pointers to Functions
    By samus250 in forum C Programming
    Replies: 15
    Last Post: 03-20-2008, 03:13 PM
  2. Pointers to Class Member Functions
    By Dark_Phoenix in forum C++ Programming
    Replies: 6
    Last Post: 09-02-2007, 02:21 PM
  3. Reg pointers to functions
    By sowmi in forum C Programming
    Replies: 1
    Last Post: 06-22-2007, 12:08 AM
  4. Header File Question(s)
    By AQWst in forum C++ Programming
    Replies: 10
    Last Post: 12-23-2004, 11:31 PM
  5. pointers, functions, parameters
    By sballew in forum C Programming
    Replies: 3
    Last Post: 11-11-2001, 10:33 PM

Tags for this Thread