Sun Studio 12: C User's Guide

Chapter 2 C-Compiler Information Specific to Sun’s Implementation

This chapter documents those areas specific to the C compiler. The information is organized into language extensions and the environment.

The C compiler is compatible with some of the features of the C language described in the new ISO C standard, ISO/IEC 9899-1999. If you wish to compile code that is compatible with the previous C standard, ISO/IEC 9889-1990 standard (and amendment 1), use -xc99=none and the compiler disregards the enhancements of the ISO/IEC 9899-1999 standard.

2.1 Constants

This section contains information related to constants that are specific to the Sun C compiler.

2.1.1 Integral Constants

Decimal, octal, and hexadecimal integral constants can be suffixed to indicate type, as shown in the following table.

Table 2–1 Data Type Suffixes

Suffix  

Type  

u or U

unsigned

l or L

long

ll or LL

long long [The long long and unassigned long long are not available with -xc99=none and -Xc mode.]

lu, LU, Lu, lU, ul, uL, Ul, or UL

unsigned long

llu, LLU, LLu, llU, ull, ULL, uLL, Ull

unsigned long long

With the -xc99=all, the compiler uses the first item of the following list in which the value can be represented, as required by the size of the constant:

The compiler issues a warning if the value exceeds the largest value a long long int can represent.

With the -xc99=none, the compiler uses the first item of the following list in which the value can be represented, as required by the size of the constant, when assigning types to unsuffixed constants:

2.1.2 Character Constants

A multiple-character constant that is not an escape sequence has a value derived from the numeric values of each character. For example, the constant ’123’ has a value of:

0

’3’

’2’

’1’

or 0x333231.

With the -Xs option and in other, non-ISO versions of C, the value is:

0

’1’

’2’

’3’

or 0x313233.

2.2 Linker Scoping Specifiers

Use the following declaration specifiers to help hide declarations and definitions of extern symbols. By using these specifiers, you no longer need to use mapfiles for linker scoping. You can also control the default setting for variable scoping by specifying -xldscope on the command line. For more information, see B.2.96 -xldscope={v}.

Table 2–2 Declaration Specifiers

Value  

Meaning  

__global

The symbol has global linker scoping and is the least restrictive linker scoping. All references to the symbol bind to the definition in the first dynamic module that defines the symbol. This linker scoping is the current linker scoping for extern symbols.

__symbolic

The symbol has symbolic linker scoping and is more restrictive than global linker scoping. All references to the symbol from within the dynamic module being linked bind to the symbol defined within the module. Outside of the module, the symbol appears as though it were global. This linker scoping corresponds to the linker option -Bsymbolic. For more information on the linker, see ld(1).

__hidden

The symbol has hidden linker scoping. Hidden linker scoping is more restrictive than symbolic and global linker scoping. All references within a dynamic module bind to a definition within that module. The symbol will not be visible outside of the module.

An object or function may be redeclared with a more restrictive specifier, but may not be redeclared with a less restrictive specifier. A symbol may not be declared with a different specifier once the symbol has been defined.

__global is the least restrictive scoping, __symbolic is more restrictive, and __hidden is the most restrictive scoping.

2.3 Thread Local Storage Specifier

Take advantage of thread-local storage by declaring thread-local variables. A thread-local variable declaration consists of a normal variable declaration with the addition of the variable specifier __thread. For more information, see B.2.146 -xthreadvar[=o].

You must include the __thread specifier in the first declaration of the thread variable in the source file being compiled.

You can only use the __thread specifier in the declaration of an object with static storage duration. You can statically initialize a thread variable as you would any other object of static-storage duration.

Variables that you declare with the __thread specifier have the same linker binding as they would without the __thread specifier. This includes tentative definitions, such as declarations without initializers.

The address of a thread variable is not a constant. Therefore, the address-of operator (&) for a thread variable is evaluated at run time and returns the address of the thread variable for the current thread. As a consequence, objects of static storage duration are initialized dynamically to the address of a thread variable.

The address of a thread variable is stable for the lifetime of the corresponding thread. Any thread in the process can freely use the address of a thread variable during the variable’s lifetime. You cannot use a thread variable’s address after its thread terminates. After a thread terminates, all addresses of that thread’s variables are invalid.

2.4 Floating Point, Nonstandard Mode

IEEE 754 floating-point default arithmetic is “nonstop.” Underflows are “gradual.” The following is a summary, see the Numerical Computation Guide for details.

Nonstop means that execution does not halt on occurrences like division by zero, floating-point overflow, or invalid operation exceptions. For example, consider the following, where x is zero and y is positive:

z = y / x;

By default, z is set to the value +Inf, and execution continues. With the -fnonstd option, however, this code causes an exit, such as a core dump.

Here is how gradual underflow works. Suppose you have the following code:


x = 10;
for (i = 0; i < LARGE_NUMBER; i++)
x = x / 10;

The first time through the loop, x is set to 1; the second time through, to 0.1; the third time through, to 0.01; and so on. Eventually, x reaches the lower limit of the machine’s capacity to represent its value. What happens the next time the loop runs?

Let’s say that the smallest number characterizable is 1.234567e-38

The next time the loop runs, the number is modified by “stealing” from the mantissa and “giving” to the exponent so the new value is 1.23456e-39 and, subsequently, 1.2345e-40 and so on. This is known as “gradual underflow,” which is the default behavior. In nonstandard mode, none of this “stealing” takes place; typically, x is simply set to zero.

2.5 Labels as Values

The C compiler recognizes the extension to C known as computed goto. Computed goto enables runtime determination of branching destinations. The address of a label can be acquired by using the ’&&’ operator and assigned to a pointer of type void *:


void *ptr;
...
ptr = &&label1;

A later goto statement can branch to label1 through ptr:


goto *ptr;

Because ptr is computed at runtime, ptr can take on the address of any label that is in-scope and the goto statement can branch to it.

One way of using computed goto is for the implementation of a jump table:


static void *ptrarray[] = { &&label1, &&label2, &&label3 };

Now the array elements can be selected by indexing:


goto *ptrarray[i];

Addresses of labels can only be computed from the current function scope. Attempting to take addresses of labels out of the current function yields unpredictable results.

The jump table works similarly to a switch statement though there are some key differences and the jump table can make it more difficult to follow program flow. A notable difference is that the switch-statement jump-destinations are all in the forward direction from the switch reserved word; using computed goto to implement a jump table enables branching in both forward and reverse directions.


#include <stdio.h>
void foo()
{
  void *ptr;

  ptr = &&label1;

  goto *ptr;

  printf("Failed!\n");
  return;

  label1:
  printf("Passed!\n");
  return;
}

int main(void)
{
  void *ptr;

  ptr = &&label1;

  goto *ptr;

  printf("Failed!\n");
  return 0;

  label1:
  foo();
  return 0;
}

The following example also makes use of a jump table to control program flow:


#include <stdio.h>

int main(void)
{
  int i = 0;
  static void * ptr[3]={&&label1, &&label2, &&label3};

  goto *ptr[i];

  label1:
  printf("label1\n");
  return 0;

  label2:
  printf("label2\n");
  return 0;

  label3:
  printf("label3\n");
  return 0;
}

%example: a.out
%example: label1

Another application of computed goto is as an interpreter for threaded code. The label addresses within the interpreter function can be stored in the threaded code for fast dispatching.

Here is an alternate way to write the above example:


static const int ptrarray[] = { &&label1 - &&label1, &&label2 - &&label1, &&label3 - &&label1 };
goto *(&&label1 + ptrarray[i]);

This is more efficient for shared library code, as it reduces the number of dynamic relocations that are needed, and by consequence, allows the data (ptrarray elements) to be read-only.

2.6 long long Data Type

When you compile with -xc99=none, the Sun C compiler includes the data-types long long, and unsigned long long, which are similar to the data-type long. The long long data-type stores 64 bits of information; long stores 32 bits of information on SPARC V8 and x86. The long data-type stores 64 bits on SPARC V9. The long long data-type is not available in -Xc mode.

2.6.1 Printing long long Data Types

To print or scan long long data types, prefix the conversion specifier with the letters ll. For example, to print llvar, a variable of long long data type, in signed decimal format, use:


printf("%lld\n", llvar);

2.6.2 Usual Arithmetic Conversions

Some binary operators convert the types of their operands to yield a common type, which is also the type of the result. These are called the usual arithmetic conversions:

2.7 Assertions

A line of the form:


#assert predicate (token-sequence)

associates the token-sequence with the predicate in the assertion name space (separate from the space used for macro definitions). The predicate must be an identifier token.


#assert predicate

asserts that predicate exists, but does not associate any token sequence with it.

The compiler provides the following predefined predicates by default (not in -Xc mode):


#assert system (unix)
#assert machine (sparc)
#assert machine (i386)(x86)
#assert cpu (sparc)
#assert cpu (i386)(x86)

lint provides the following predefinition predicate by default (not in -Xc mode):


#assert lint (on)

Any assertion may be removed by using #unassert, which uses the same syntax as assert. Using #unassert with no argument deletes all assertions on the predicate; specifying an assertion deletes only that assertion.

An assertion may be tested in a #if statement with the following syntax:


#if #predicate(non-empty token-list)

For example, the predefined predicate system can be tested with the following line:


#if #system(unix)

which evaluates true.

2.8 Pragmas

Preprocessing lines of the form:


#pragma pp-tokens

specify implementation-defined actions.

The following #pragmas are recognized by the compilation system. The compiler ignores unrecognized pragmas. Using the -v option will give a warning for unrecognized pragmas.

2.8.1 align

#pragma align integer (variable[, variable])

The align pragma makes all the mentioned variables memory aligned to integer bytes, overriding the default. The following limitations apply:


#pragma align 64 (aninteger, astring, astruct)
int aninteger;
static char astring[256];
struct astruct{int a; char *b;};

2.8.2 c99

#pragma c99(“implicit” | “no%implicit”)

This pragma controls diagnostics for implicit function declarations. If the c99 pragma value is set to “implicit”, note the use of quotation marks, a warning is generated when the compiler finds an implicit function declaration. If the c99 pragma value is set to “no%implicit”, note the use of quotation marks, the compiler silently accepts implicit function declaration until the pragma value is reset.

The value of the -xc99 option impacts this pragma. If -xc99=all, the pragma is set to #pragma c99(“implicit”) and when -xc99=none, the pragma is set to #pragma c99(“no%implicit”).

This pragma is set to c99=(“implicit”) by default.

2.8.3 does_not_read_global_data

#pragma does_not_read_global_data (funcname [, funcname])

This pragma asserts that the specified list of routines do not read global data directly or indirectly. This allows for better optimization of code around calls to such routines. In particular, assignment statements or stores could be moved around such calls.

The specified functions must be declared with a prototype or empty parameter list prior to this pragma. If the assertion about global access is not true, then the behavior of the program is undefined.

2.8.4 does_not_return

#pragma does_not_return (funcname [, funcname])

This pragma is an assertion to the compiler that the calls to the specified routines will not return. This allows the compiler to perform optimizations consistent with that assumption. For example, register life-times will terminate at the call sites which in turn allows more optimizations.

If the specified function does return, then the behavior of the program is undefined. This pragma is permitted only after the specified functions are declared with a prototype or empty parameter list as the following example shows:


extern void exit(int);
#pragma does_not_return(exit)

extern void __assert(int);
#pragma does_not_return(__assert)

2.8.5 does_not_write_global_data

#pragma does_not_write_global_data (funcname [, funcname])

This pragma asserts that the specified list of routines do not write global data directly or indirectly. This allows for better optimization of code around calls to such routines. In particular, assignment statements or stores could be moved around such calls.

The specified functions must be declared with a prototype or empty parameter list prior to this pragma. If the assertion about global access is not true, then the behavior of the program is undefined.

2.8.6 error_messages

#pragma error_messages (on|off|default, tag… tag)

The error message pragma provides control within the source program over the messages issued by the C compiler and lint. For the C compiler, the pragma has an effect on warning messages only. The -w option of the C compiler overrides this pragma by suppressing all warning messages.

2.8.7 fini

#pragma fini (f1[, f2…,fn]

Causes the implementation to call functions f1 to fn (finalization functions) after it calls main() routine. Such functions are expected to be of type void and to accept no arguments, and are called either when a program terminates under program control or when the containing shared object is removed from memory. As with “initialization functions,” finalization functions are executed in the order processed by the link editors.

You should be careful when a finalization function affects the global-program state. For example, unless an interface explicitly states what happens when you use a system-library finalization-function, you should capture and restore any global state information, such as the value of errno, that the system-library finalization-function may change.

2.8.8 hdrstop

#pragma hdrstop

The hdrstop pragma must be placed after the last header file to identify the end of the viable prefix in each source file that is to share the same precompiled-header file. For example, consider the following files:


example% cat a.c
#include "a.h"
#include "b.h"
#include "c.h"
#include <stdio.h>
#include "d.h"
.
.
.
example% cat b.h
#include "a.h"
#include "b.h"
#include "c.h"

The viable source prefix ends at c.h so you would insert a #pragma hdrstop after c.h in each file.

#pragma hdrstop must only appear at the end of the viable prefix of a source file that is specified with the cc command. Do not specify #pragma hdrstop in any include file.

2.8.9 ident

#pragma ident string

Places string in the .comment section of the executable.

2.8.10 init

#pragma init (f1[, f2…,fn])

Causes the implementation to call functions f1 to fn (initialization functions) before it calls main(). Such functions are expected to be of type void and to accept no arguments, and are called while constructing the memory image of the program at the start of execution. In the case of initializers in a shared object, they are executed during the operation that brings the shared object into memory, either program start-up or some dynamic loading operation, such as dlopen(). The only ordering of calls to initialization functions is the order in which they were processed by the link editors, both static and dynamic.

You should be careful when an initialization function affects the global-program state. For example, unless an interface explicitly states what happens when you use a system-library initialization-function, you should capture and restore any global state information, such as the value of errno, that the system-library initialization-function may change.

2.8.11 inline

#pragma [no_]inline (funcname[, funcname])

This pragma controls the inlining of routine names listed in the argument of the pragma. The scope of this pragma is over the entire file. Only global inlining control is allowed, call-site specific control is not permitted by this pragma.

If you use #pragma inline, it provides a suggestion to the compiler to inline the calls in the current file that match the list of routines listed in the pragma. This suggestion may be ignored under certain cases. For example, the suggestion is ignored when the body of the function is in a different module and the crossfile option is not used.

If you use #pragma no_inline, it provides a suggestion to the compiler to not inline the calls in the current file that match the list of routines listed in the pragma.

Both #pragma inline and #pragma no_inline are permitted only after the function is declared with a prototype or empty parameter list as the following example shows:


static void foo(int);
static int bar(int, char *);
#pragma inline(foo, bar)

See also -xldscope, -xinline, -xO, and -xcrossfile.

2.8.12 int_to_unsigned

#pragma int_to_unsigned (funcname)

For a function that returns a type of unsigned, in -Xt or -Xs mode, changes the function return to be of type int.

2.8.13 MP serial_loop

(SPARC) #pragma MP serial_loop


Note –

The Sun-specific MP pragmas have been deprecated and are no longer supported. However, the compiler supports the APIs specified by the OpenMP 2.5 standard instead. See the OpenMP API User’s Guide for migration information to the directives of the standard.


Refer to 3.8.3.1 Serial Pragmas for details.

2.8.14 MP serial_loop_nested

(SPARC) #pragma MP serial_loop_nested


Note –

The Sun-specific MP pragmas have been deprecated and are no longer supported. However, the compiler supports the APIs specified by the OpenMP 2.5 standard instead. See the Sun Studio 12: OpenMP API User’s Guidefor migration information to the directives of the standard.


Refer to 3.8.3.1 Serial Pragmas for details.

2.8.15 MP taskloop

(SPARC) #pragma MP taskloop


Note –

The Sun-specific MP pragmas have been deprecated and are no longer supported. However, the compiler supports the APIs specified by the OpenMP 2.5 standard instead. See the OpenMP API User’s Guide for migration information to the directives of the standard.


Refer to 3.8.3.2 Parallel Pragma for details.

2.8.16 nomemorydepend

(SPARC) #pragma nomemorydepend

This pragma specifies that for any iteration of a loop, there are no memory dependences. That is, within any iteration of a loop there are no references to the same memory. This pragma will permit the compiler (pipeliner) to schedule instructions, more effectively, within a single iteration of a loop. If any memory dependences exist within any iteration of a loop, the results of executing the program are undefined. The compiler takes advantage of this information at optimization level of 3 or above.

The scope of this pragma begins with the pragma and ends with which ever of the following occurs first: the beginning of the next block, the next for loop within the current block, the end of the current block. The pragma applies to the next for loop prior to the end of the pragmas scope.

2.8.17 no_side_effect

(SPARC) #pragma no_side_effect(funcname[, funcname…])

funcname specifies the name of a function within the current translation unit. The function must be declared with a prototype or empty parameter list prior to the pragma. The pragma must be specified prior to the function’s definition. For the named function, funcname, the pragma declares that the function has no side effects of any kind. This means that funcname returns a result value that depends only on the passed arguments. In addition, funcname and any called descendants:

The compiler can use this information when doing optimizations using the function. If the function does have side effects, the results of executing a program which calls this function are undefined. The compiler takes advantage of this information at optimization level of 3 or above.

2.8.18 opt

#pragma opt level (funcname[, funcname])

funcname specifies the name of a function defined within the current translation unit. The value of level specifies the optimization level for the named function. You can assign optimization levels 0, 1, 2, 3, 4, 5. You can turn off optimization by setting level to 0. The functions must be declared with a prototype or empty parameter list prior to the pragma. The pragma must proceed the definitions of the functions to be optimized.

The level of optimization for any function listed in the pragma is reduced to the value of -xmaxopt. The pragma is ignored when -xmaxopt=off.

2.8.19 pack

#pragma pack(n)

Use #pragma pack(n)to affect member packing of a structure or a union. By default, members of a structure or union are aligned on their natural boundaries; one byte for a char, two bytes for a short, four bytes for an integer etc. If n is present, it must be a power of 2 specifying the strictest natural alignment for any structure or union member. Zero is not accepted.

You can use #pragma pack(n) to specify an alignment boundary for a structure or union member. For example, #pragma pack(2) aligns int, long, long long, float, double, long double, and pointers on two byte boundaries instead of their natural alignment boundaries.

If n is the same or greater than the strictest alignment on your platform, (four on x86, eight on SPARC v8, and 16 on SPARC v9), the directive has the effect of natural alignment. Also, if n is omitted, member alignment reverts to the natural alignment boundaries.

The #pragma pack(n) directive applies to all structure or union definitions which follow it until the next pack directive. If the same structure or union is defined in different translation units with different packing, your program may fail in unpredictable ways. In particular, you should not use #pragma pack(n) prior to including a header that defines the interface of a precompiled library. The recommended usage of #pragma pack(n) is to place it in your program code immediately before any structure or union to be packed. Follow the packed structure immediately with #pragma pack( ).

Note that when you use #pragma pack, the alignment of the packed structure or union itself is the same as its more strictly aligned member. Therefore any declaration of that struct or union will be at the pack alignment. For example, a struct with only chars has no alignment restrictions, whereas a struct containing a double would be aligned on an 8-byte boundary.


Note –

If you use #pragma pack to align struct or union members on boundaries other than their natural boundaries, accessing these fields usually leads to a bus error on SPARC. In order to avoid such an error, be sure to also specify the -xmemalign option. See B.2.111 -xmemalign=ab , for the optimal way to compile such programs.


2.8.20 pipeloop

(SPARC) #pragma pipeloop(n)

This pragma accepts a positive constant integer value, or 0, for the argument n. This pragma specifies that a loop is pipelineable and the minimum dependence distance of the loop-carried dependence is n. If the distance is 0, then the loop is effectively a Fortran-style doall loop and should be pipelined on the target processors. If the distance is greater than 0, then the compiler (pipeliner) will only try to pipeline n successive iterations. The compiler takes advantage of this information at optimization level of 3 or above.

The scope of this pragma begins with the pragma and ends with which ever of the following occurs first: the beginning of the next block, the next for loop within the current block, the end of the current block. The pragma applies to the next for loop prior to the end of the pragmas scope.

2.8.21 rarely_called

#pragma rarely_called(funcname[, funcname])

This pragma provides a hint to the compiler that the specified functions are called infrequently. This allows the compiler to perform profile-feedback style optimizations on the call-sites of such routines without the overhead of a profile-collections phase. Since this pragma is a suggestion, the compiler may not perform any optimizations based on this pragma.

The specified functions must be declared with a prototype or empty parameter list prior to this pragma. The following is an example of #pragma rarely_called:


extern void error (char *message);
#pragma rarely_called(error)

2.8.22 redefine_extname

#pragma redefine_extname old_extname new_extname

This pragma causes every externally defined occurrence of the name old_extname in the object code to be replaced by new_extname. As a result, the linker only sees the name new_extname at link time. If #pragma redefine_extname is encountered after the first use of old_extname, as a function definition, an initializer, or an expression, the effect is undefined. (This pragma is not supported in– Xs mode.)

When #pragma redefine_extname is available, the compiler provides a definition of the predefined macro __PRAGMA_REDEFINE_EXTNAME, which lets you write portable code that works both with and without #pragma redefine_extname.

The purpose of #pragma redefine_extname is to allow an efficient means of redefining a function interface when the name of the function cannot be changed. For example, when the original function definition must be maintained in a library, for compatibility with existing programs, along with a new definition of the same function for use by new programs. This can be accomplished by adding the new function definition to the library by a new name. Consequently, the header file that declares the function uses #pragma redefine_extname so that all of the uses of the function are linked with the new definition of that function.


#if    defined(__STDC__)

#ifdef __PRAGMA_REDEFINE_EXTNAME
extern int myroutine(const long *, int *);
#pragma redefine_extname myroutine __fixed_myroutine
#else /* __PRAGMA_REDEFINE_EXTNAME */

static int
myroutine(const long * arg1, int * arg2)
{
    extern int __myroutine(const long *, int*);
    return (__myroutine(arg1, arg2));
}
#endif /* __PRAGMA_REDEFINE_EXTNAME */

#else /* __STDC__ */

#ifdef __PRAGMA_REDEFINE_EXTNAME
extern int myroutine();
#pragma redefine_extname myroutine __fixed_myroutine
#else /* __PRAGMA_REDEFINE_EXTNAME */

static int
myroutine(arg1, arg2)
    long *arg1;
    int *arg2;
{
    extern int __fixed_myroutine();
    return (__fixed_myroutine(arg1, arg2));
}
#endif /* __PRAGMA_REDEFINE_EXTNAME */

#endif /* __STDC__ */

2.8.23 returns_new_memory

#pragma returns_new_memory (funcname[, funcname])

This pragma asserts that the return value of the specified functions does not alias with any memory at the call site. In effect, this call returns a new memory location. This informations allows the optimizer to better track pointer values and clarify memory location. This results in improved scheduling, pipelining, and parallelization of loops. However, if the assertion is false, the behavior of the program is undefined.

This pragma is permitted only after the specified functions are declared with a prototype or empty parameter list as the following example shows:


void *malloc(unsigned);
#pragma returns_new_memory(malloc)

2.8.24 unknown_control_flow

#pragma unknown_control_flow (funcname[, funcname])

In order to describe procedures that alter the flow graphs of their callers, the C compiler provides the #pragma unknown_control_flow directive. Typically, this directive accompanies declarations of functions like setjmp(). On Sun systems, the include file <setjmp.h> contains the following:


extern int setjmp();
#pragma unknown_control_flow(setjmp)

Other functions with properties like those of setjmp() must be declared similarly.

In principle, an optimizer that recognizes this attribute could insert the appropriate edges in the control flow graph, thus handling function calls safely in functions that call setjmp(), while maintaining the ability to optimize code in unaffected parts of the flow graph.

The specified functions must be declared with a prototype or empty parameter list prior to this pragma.

2.8.25 unroll

(SPARC) #pragma unroll (unroll_factor)

This pragma accepts a positive constant integer value for the argument unroll_factor. For unroll factor other than 1, this directive serves as a suggestion to the compiler that the specified loop should be unrolled by the given factor. The compiler will, when possible, use that unroll factor. When the unroll factor value is 1, this directive serves as a command which specifies to the compiler that the loop is not to be unrolled. The compiler takes advantage of this information at optimization level of 3 or above.

The scope of this pragma begins with the pragma and ends with which ever of the following occurs first: the beginning of the next block, the next for loop within the current block, the end of the current block. The pragma applies to the next for loop prior to the end of the pragmas scope.

2.8.26 warn_missing_parameter_info

#pragma [no_]warn_missing_parameter_info

When you specify #pragma warn_missing_parameter_info, the compiler issues a warning for a function call whose function declaration contains no parameter type information. Consider the following example:


exmaple% cat -n t.c
     1    #pragma warn_missing_parameter_info
     2    
     3    int foo();
     4    
     5    int bar () {
     6    
     7       int i;
     8    
     9       i = foo(i);
    10    
    11       return i;
    12    }
% cc t.c -c -errtags
"t.c", line 9: warning: function foo has no prototype (E_NO_MISSED_PARAMS_ALLOWED)
example%

#pragma no_warn_missing_parameter_info turns off the effect of any previous #pragma warn_missing_parameter_info.

By default, #pragma no_warn_missing_parameter_info is in effect.

2.8.27 weak

#pragma weak symbol1 [= symbol2]

Defines a weak global symbol. This pragma is used mainly in source files for building libraries. The linker does not produce an error message if it is unable to resolve a weak symbol.


#pragma weak symbol

defines symbol to be a weak symbol. The linker does not produce an error message if it does not find a definition for symbol.


#pragma weak symbol1 = symbol2

defines symbol1 to be a weak symbol, which is an alias for the symbol symbol2. This form of the pragma can only be used in the same translation unit where symbol2 is defined, either in the sourcefiles or one of its included headerfiles. Otherwise, a compilation error will result.

If your program calls but does not define symbol1, and symbol1 is a weak symbol in a library being linked, the linker uses the definition from that library. However, if your program defines its own version of symbol1, then the program’s definition is used and the weak global definition of symbol1 in the library is not used. If the program directly calls symbol2, the definition from the library is used; a duplicate definition of symbol2 causes an error.

2.9 Predefined Names

The following identifier is predefined as an object-like macro:

Table 2–3 Predefined Identifier

Identifier  

Description  

__STDC__

__STDC__ 1 -Xc

__STDC__ 0 -Xa, -Xt

Not defined -Xs

The compiler issues a warning if __STDC__ is undefined (#undef __STDC__). __STDC__ is not defined in -Xs mode.

Predefinitions (not valid in -Xc mode):

The following predefinitions are valid in all modes:

The compiler also predefines the object-like macro __PRAGMA_REDEFINE_EXTNAME to indicate that the pragma will be recognized. The following is predefined in -Xa and -Xt modes only:

__RESTRICT

2.10 The Value of errno

If you specify -fast, you should not rely on the value of errno because the value can change as a result of code optimization. The easiest way to avoid this problem is to not specify -fast.

If, however, you specify -fast and you are relying on the value of errno, do the following:

2.11 _Restrict Keyword

The C compiler supports the _Restrict keyword as an equivalent to the restrict keyword in the C99 standard. The _Restrict keyword is available with -xc99=none and -xc99=all, whereas the restrict keyword is only available with -xc99=all.

For more information on supported C99 features, see Table C–6.

2.12 _ _asm Keyword

The _ _asm keyword (note the initial double-underscore) is a synonym for the asm keyword. If you use asm, rather than _ _asm, and compile in– Xc mode, the compiler issues a warning. The compiler does not issue a warning if you use _ _asm in– Xc mode. The _ _asm statement has the form:


_ _asm("string");

where string is a valid assembly language statement. The _ _asm statements must appear within function bodies.

2.13 Environment Variables

This section lists the environment variables that let you control the compilation and runtime environment.

2.13.1 OMP_DYNAMIC

Enable or disable dynamic adjustment of the number of threads.

2.13.2 OMP_NESTED

Enable or disable nested parallelism.

2.13.3 OMP_NUM_THREADS

Set the number of threads to use during execution.

2.13.4 OMP_SCHEDULE

Set the run-time schedule type and chunk size.

2.13.5 PARALLEL

(SPARC) Specifies the number of processors available to the program for multiprocessor execution. If the target machine has multiple processors, the threads can map to independent processors. Running the program leads to the creation of two threads that execute the parallelized portions of the program.

2.13.6 SUN_PROFDATA

Controls the name of the file in which the -xprofile=collect command stores execution-frequency data.

2.13.7 SUN_PROFDATA_DIR

Controls in which directory the -xprofile=collect command places the execution-frequency data-file.

2.13.8 SUNW_MP_THR_IDLE

Controls end-of-task status of each helper thread and can be set to spin ns, or sleep nms. The default is sleep. See the OpenMP API User’s Guide for details.

2.13.9 TMPDIR

cc normally creates temporary files in the directory /tmp. You can specify another directory by setting the environment variable TMPDIR to the directory of your choice. However, if TMPDIR is not a valid directory, cc uses /tmp. The -xtemp option has precedence over the TMPDIR environment variable.

If you use a Bourne shell, type:


$ TMPDIR=dir; export TMPDIR

If you use a C shell, type:


% setenv TMPDIR dir

2.14 How to Specify Include Files

To include any of the standard header files supplied with the C compilation system, use this format:


#include <stdio.h>

The angle brackets (<>) cause the preprocessor to search for the header file in the standard place for header files on your system, usually the /usr/include directory.

The format is different for header files that you have stored in your own directories:


#include "header.h"

For statements of the form #include "foo.h" (where quotation marks are used), the compiler searches for include files in the following order:

  1. The current directory (that is, the directory containing the “including” file)

  2. The directories named with -I options, if any

  3. The /usr/include directory

If your header file is not in the same directory as the source files that include it, specify the path of the directory in which it is stored with the– I option to cc. Suppose, for instance, that you have included both stdio.h and header.h in the source file mycode.c:


#include <stdio.h>
#include "header.h"

Suppose further that header.h is stored in the directory../defs. The command:


% cc– I../defs mycode.c

directs the preprocessor to search for header.h first in the directory containing mycode.c, then in the directory ../defs, and finally in the standard place. It also directs the preprocessor to search for stdio.h first in ../defs, then in the standard place. The difference is that the current directory is searched only for header files whose names you have enclosed in quotation marks.

You can specify the– I option more than once on the cc command-line. The preprocessor searches the specified directories in the order they appear. You can specify multiple options to cc on the same command-line:


% cc– o prog– I../defs mycode.c

2.14.1 Using the -I- Option to Change the Search Algorithm

The new -I- option gives more control over the default search rules. Only the first -I- option on the command line works as described in this section. When -I- appears in the command line:

For include files of the form #include "foo.h", search the directories in the following order:

1. The directories named with -I options (both before and after -I-).

2. The directories for compiler-provided C++ header files, ANSI C header files, and special-purpose files.

3. The /usr/include directory.

For include files of the form #include <foo.h>, search the directories in the following order:

1.The directories named in the -I options that appear after -I-.

2. The directories for compiler-provided C++ header files, ANSI C header files, and special-purpose files.

3. The /usr/include directory.

The following example shows the results of using -I- when compiling prog.c.


prog.c
#include "a.h"

#include <b.h>

#include "c.h"


c.h
#ifndef _C_H_1

#define _C_H_1

int c1;

#endif


int/a.h
#ifndef _A_H

#define _A_H

#include "c.h"

int a;

#endif


int/b.h
#ifndef _B_H

#define _B_H

#include <c.h>

int b;

#endif
int/c.h
#ifndef _C_H_2

#define _C_H_2

int c2;

#endif

The following command shows the default behavior of searching the current directory (the directory of the including file) for include statements of the form #include "foo.h". When processing the #include "c.h" statement in inc/a.h, the preprocessor includes the c.h header file from the inc subdirectory. When processing the #include "c.h" statement in prog.c, the preprocessor includes the c.h file from the directory containing prog.c. Note that the -H option instructs the compiler to print the paths of the included files.


example% cc -c -Iinc -H prog.c
inc/a.h
            inc/c.h
inc/b.h
            inc/c.h
c.h

The next command shows the effect of the -I- option. The preprocessor does not look in the including directory first when it processes statements of the form #include "foo.h". Instead, it searches the directories named by the -I options in the order that they appear in the command line. When processing the #include "c.h" statement in inc/a.h, the preprocessor includes the ./c.h header file instead of the inc/c.h header file.


example% cc -c -I. -I- -Iinc -H prog.c
inc/a.h
            ./c.h
inc/b.h
            inc/c.h
./c.h

2.14.1.1 Warnings

Never specify the compiler installation area, /usr/include, /lib, or /usr/lib, as search directories.

For more information, see B.2.34 -I[-|dir].