Douglas Walls' Weblog

« Previous month (Apr 2006) | Main | Next month (Jun 2006) »
20060522 Monday May 22, 2006

C99 inline function and the Sun C Compiler
Note, the C standard says that inline is only a suggestion to the C compiler.  The C compiler can choose not to inline anything, and attempt to call the actual function.

The Sun C compiler does not inline C function calls unless optimizing at -xO3 or above.  And that inlining is done by the backends.  And then only if the backend's heuristics decide it is profitable to do so.  The Sun C compiler gives no way to force a function to be inlined.

For static inline functions it is simple.  Either a function defined with the inline function specifier is inlined at a reference or a call is made to the actual function.  The compiler can choose which to do at each reference.  The Sun C compiler decides if it is profitable to inline at -xO3 and above.  When not profitable to inline, or at an optimization of less than -xO3 a reference to the actual function will be generated.  If any reference to the actual function is generated the function definition will be generated in the object code.  Note if the address of the function is taken, the actual function will be generated in the object code.

Extern inline functions are more complicated.  There are two types of extern inline functions, an inline definition which never provides an extern (global) definition of the function and an extern inline function which always provide a global definition of the function.  To quote the C99 standard:

       [#6]  Any  function  with  internal linkage can be an inline
function. For a function with external linkage, the
following restrictions apply: If a function is declared with
an inline function specifier, then it shall also be defined
in the same translation unit. If all of the file scope
declarations for a function in a translation unit include
the inline function specifier without extern, then the
definition in that translation unit is an inline definition.
An inline definition does not provide an external definition
for the function, and does not forbid an external definition
in another translation unit. An inline definition provides
an alternative to an external definition, which a translator
may use to implement any call to the function in the same
translation unit. It is unspecified whether a call to the
function uses the inline definition or the external
definition.

[#7] EXAMPLE The declaration of an inline function with
external linkage can result in either an external
definition, or a definition available for use only within
the translation unit. A file scope declaration with extern
creates an external definition. The following example shows
an entire translation unit.

inline double fahr(double t)
{
return (9.0 * t) / 5.0 + 32.0;
}

inline double cels(double t)
{
return (5.0 * (t - 32.0)) / 9.0;
}

extern double fahr(double); // creates an external definition

double convert(int is_fahr, double temp)
{
/* A translator may perform inline substitutions */
return is_fahr ? cels(temp) : fahr(temp);
}

[#8] Note that the definition of fahr is an external
definition because fahr is also declared with extern, but
the definition of cels is an inline definition. Because
cels has external linkage and is referenced, an external
definition has to appear in another translation unit (see
6.9); the inline definition and the external definition are
distinct and either may be used for the call.

So, for an inline definition, the programmer is required to supply an extern definition of the function in another translation-unit for references to the function that are not inlined.

For an inline definition, the compiler must not create a global definition of the function.  That means any reference to an inline definition that is not inlined must be a reference to a global function defined elsewhere.  Put another way, the object file produced by compiling this translation unit will not contain a global symbol for the inline definition.  And any reference to the function that is not inlined will be to an extern (global) symbol provided by some other object file or library at link time.

For an extern inline function declared by a file scope declaration with the extern storage-class-specifier (i.e. the function definition and/or prototype), the compiler must provide a global definition of the function in the resulting object file.  The compiler can choose to inline any references to that function seen in the translation unit where the function definition has been provided, or the compiler can choose to call the global function.

The behavior of any program that relies on whether or not a function call is actually inlined, is undefined.

Note also an inline function with external linkage may not declare or reference a static variable anywhere in the translation-unit.

Definition of translation-unit: A source file and all of its includes, recursively.

Like it does for static functions, the Sun C compiler decides if it is profitable to inline a reference to an inline definition or an extern inline function at -xO3 and above.  When not profitable to inline, or at an optimization of less than -xO3 a reference to the global function will be generated.  Likewise a reference to the address of the function is always a reference to the global function.

The rules for C++ differ: a function which is inline anywhere must be inline everywhere and must be defined identically in all the translation units that use it.

gcc

The GNU C rules differ and are described in the GNU C manual, which can be found here http://gcc.gnu.org.

Sun C compiler gcc compatibility for inline functions

To obtain behavior from the Sun C compiler that is compatible with gcc's implementation of extern inline functions for most programs, use the -features=no%extinl flag.  When this flag is specified the Sun C compiler will treat the function as if it was declared as a static inline function.

The one place this is not compatible will be when the address of the function is taken.  With gcc this will be an address of a global function, and with Sun's compiler the local static definition address will be used.

( May 22 2006, 08:11:19 AM PDT ) Permalink Comments [1]

20060508 Monday May 08, 2006

Finding the canonical path to an executable
Below is a coding example of how an executable can determine the canonical path to itself on the file system.  Compiler drivers, like cc, CC, f95 need to do this in order to exec the component executables that compile a program.  For example, the compiler front-end, an optimizer, and a linker.

% cat findself.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef MAXPATHLEN
#define MAXPATHLEN      1024
#endif

/* find_run_directory - find executable file in PATH
 * PARAMETERS:
 *      cmd     filename as typed by user
 *      cwd     where to return working directory
 *      dir     where to return program's directory
 *      run     where to return final resolution name
 * RETURNS:
 *      returns zero for success,
 *      -1 for error (with errno set properly).
 */
int
find_run_directory (char *cmd, char *cwd, char *dir, char **run)
{
    char                *s;

    if (!cmd || !*cmd || !cwd || !dir) {
        errno = EINVAL;         /* stupid arguments! */
        return -1;
    }

    if (*cwd != '/')
        if (getcwd (cwd, MAXPATHLEN - 1) == NULL )
            return -1;          /* cant get working directory */

    if (strchr (cmd, '/') != NULL) {
        if (realpath(cmd, dir) == NULL) {
            int lerrno = errno;
            if (chdir((const char *)cwd) == NULL)
                errno = lerrno;
            return -1;
        }
    } else {
#ifdef __linux__
        /* getexecname() not available on Linux */
        if (readlink("/proc/self/exe", dir, MAXPATHLEN) == -1) {
#else
        if (realpath(getexecname(), dir) == NULL) {
#endif
            int lerrno = errno;
            if (chdir((const char *)cwd) == NULL)
                errno = lerrno;
            return -1;
        }
    }

    s = strrchr (dir, '/');
    *s++ = 0;
    if (run)            /* user wants resolution name */
        *run = s;

    return 0;
}

char current_working_directory[MAXPATHLEN];
char run_directory[MAXPATHLEN];
char * run_exec_name = NULL;

int
main(int argc, char **argv)
{

    if ( !find_run_directory (argv[0],
                              current_working_directory,
                              run_directory, &run_exec_name) ) {
        (void)printf("argv[0] = %s\n"
                         "cwd = %s\n"
                         "run_dir = %s\n"
                         "run_exec = %s\n",
                     argv[0],
                     current_working_directory,
                     run_directory,
                     run_exec_name);
    } else {
        (void) printf("%s\n", "Unaable to find run directory.");
    }

    exit (0);
}


% cc findself.c -O -o prod/bin/findself
% ls
bin         findself.c  prod
% ls bin
findself
% ls -laF bin
total 6
drwxr-xr-x   2 me      staff        512 Mar  5 10:37 ./
drwxr-xr-x   4 me      staff        512 Mar  5 10:37 ../
lrwxrwxrwx   1 me      staff         20 Mar  5 10:37 findself -> ../prod/bin/findself*
% ls -laF prod/bin         
total 22
drwxr-xr-x   2 me      staff        512 Mar  5 10:37 ./
drwxr-xr-x   3 me      staff        512 Mar  5 10:37 ../
-rwxr-xr-x   1 me      staff       8992 Mar  5 10:37 findself*
% bin/findself
argv[0] = bin/findself
cwd = /home/me/blog
run_dir = /home/me/blog/prod/bin
run_exec = findself
% prod/bin/findself
argv[0] = prod/bin/findself
cwd = /home/me/blog
run_dir = /home/me/blog/prod/bin
run_exec = findself
% setenv PATH /home/me/bin:${PATH}
% findself
argv[0] = findself
cwd = /home/me/blog
run_dir = /home/me/blog/prod/bin
run_exec = findself
%



( May 08 2006, 06:36:27 PM PDT ) Permalink Comments [0]

20060501 Monday May 01, 2006

Special Math Functions Draft Technical Report
There were three major items to come out of the Berlin ISO C standard committee meeting which will move forward in the process of becoming Technical Reports.

I talked about the Decimal Floating Point and Bounds-checking interface Draft Technical Reports in previous blog entries:  Decimal Floating Point Types & Managed Strings.

Today, I'll briefly mention the Special Math Functions DTR, which the committee also is moving forward through the SC22 registration process.  These are essentially the same functions being adopted by C++ in their library TR, tailored to the C language.  They include, among others:
For details of the functions in the draft have a look at the last committee draft:

http://www.dkuug.dk/jtc1/sc22/wg14/www/docs/n1051.pdf

During the committee discussions it was pointed out that the values computed with special math functions are very susceptible to ‘sensitivities’ based on the input values provided.  Outside of specific ranges, the values computed are essentially useless.  Thus, implementations of these functions are not likely to be nearly as robust as implementations of the C90, and C99 math libraries.  A few functions will likely be dropped from the TR in sync with those already dropped from the C++ TR.  WG14 will extract from the existing C++ TR, account for DRs that exist for the C++ TR, have a small editorial review committee review the document, and forward it to SC22 for registration.

( May 01 2006, 11:38:46 AM PDT ) Permalink Comments [0]

Search

Calendar

Links

Navigation

Referers