Oracle Solaris Studio 12.2: C ユーザーガイド

第 2 章 C コンパイラ実装に固有の情報

この章では、C コンパイラに固有の部分について説明します。言語の拡張と環境に分けて説明します。

C コンパイラは、新しい ISO C 規格である ISO/IEC 9899-1999 で規定されている C 言語のいくつかの機能と互換性があります。従来の C 規格である ISO/IEC 9889-1990 規格 (および修正 1) と互換性のあるコードをコンパイルすることを希望する場合は、-xc99=none を使用します。その結果、コンパイラは ISO/IEC 9899-1999 規格による拡張を無視します。

2.1 定数

ここでは、Solaris Studio C コンパイラの定数に関する情報を掲載します。

2.1.1 整数定数

次の表に示すように、10 進数、8 進数、16 進数の定数に接尾辞を付けて型を示すことができます。

表 2–1 データ型の接尾辞

接尾辞  

種類  

u または U

unsigned

l または L

long

ll または LL

long long ( -xc99=none-Xc モードでは使用できません)

luLULulUuluLUlUL のいずれか

unsigned long

lluLLULLullUullULLuLLUll のいずれか

unsigned long long (-xc99=none -Xc モードでは使用できません)

-xc99=all を指定する場合、定数の大きさに応じて、次のリストから値が表現でき る最初の型を使用します。

long long int で表現できる値の最大値を超えると、コンパイラは警告を発行します。

-xc99=none を指定すると、コンパイラが接尾辞を持たない定数の型を割り当てる場合、定数の大きさに応じて、次の中から値が表現できる最初の型を使用します。

2.1.2 文字定数

エスケープシーケンスの発生しない複数バイト文字セットの値は、各文字の示す数値から派生しています。たとえば定数 ’123’ の持つ値は次のようになります。

0

’3’

’2’

’1’

あるいは 0x333231 です。

-Xs オプション使用の場合、あるいは ISO でないほかの C では、この値は次のようになります。

0

’1’

’2’

’3’

または 0x313233

2.2 リンカースコープ指示子

次の宣言指示子を使用して、extern シンボルの宣言と定義を隠せます。これらの指示子を使うと、リンカースコープのマップファイルは使用しなくてすみます。また、コマンド行で -xldscope を指定して、変数スコープのデフォルト設定を制御することもできます。詳細については、「B.2.101 -xldscope={v}」 を参照してください。

表 2–2 宣言指示子

値  

意味  

__global

シンボルは大域リンカースコープを持ち、このリンカースコープはもっとも制限の少ないリンカースコープです。シンボルに対する参照はすべて、シンボルを定義する最初の動的モジュール内の定義に結合します。このリンカースコープは、extern シンボルの現在のリンカースコープです。

__symbolic

シンボルはシンボリックリンカースコープを持ち、このリンカースコープは大域リンカースコープよりも制限されたリンカースコープです。リンクしている動的モジュール内のシンボルに対する参照はすべて、モジュール内に定義されたシンボルに結合します。モジュールの外側では、シンボルは大域と同じです。このリンカースコープはリンカーオプション -Bsymbolic に対応します。リンカーの詳細については、「ld(1)」を参照してください。

__hidden

シンボルは隠蔽リンカースコープを持ち、隠蔽リンカースコープは、シンボリックリンカースコープや大域リンカースコープよりも制限されたリンカースコープです。動的モジュール内の参照はすべて、そのモジュール内の定義に結合します。シンボルはモジュールの外側では認識されません。

オブジェクトまたは関数は、より制限された指示子で再宣言することはできますが、制限のよりゆるやかな指示子で再宣言することはできません。シンボルは一度定義したら、異なる指示子で宣言することはできません。

__global はもっとも制限の少ないスコープです。__symbolic はより制限されたスコープです。__hidden はもっとも制限の多いスコープです。

2.3 スレッドローカルな記憶領域指示子

スレッドローカルの変数を宣言して、スレッドローカルな記憶領域を利用します。スレッドローカルな変数の宣言は、通常の変数宣言に変数指示子 __thread を加えたものから成ります。詳細については、「B.2.151 -xthreadvar[= o]」 を参照してください。

__thread 指示子は、コンパイル対象のソースファイルにあるスレッド変数の最初の宣言に含める必要があります。

__thread 指示子を使用できるのは、静的記憶領域を持つオブジェクトの宣言内だけです。スレッド変数を静的に初期化する方法は、静的記憶領域のほかのオブジェクトの場合と同じです。

__thread 指示子で宣言する変数は、__thread 指示子なしで宣言する場合と同じリンカー結合を持っています。初期設定子のない宣言など、一時的な定義が含まれます。

スレッド変数のアドレスは定数ではありません。したがって、スレッド変数のアドレス演算子 (&) は実行時に評価され、現在のスレッドのスレッド変数のアドレスが返されます。結果的に、静的記憶領域のオブジェクトはスレッド変数のアドレスに動的に初期化されます。

スレッド変数のアドレスは、対応するスレッドの有効期間の間は安定しています。変数の有効期間内は、プロセス内の任意のスレッドがスレッド変数のアドレスを自由に使用できます。スレッドが終了したあとは、スレッド変数のアドレスを使用できません。スレッドの終了後は、そのスレッドの変数のアドレスはすべて無効となります。

2.4 浮動小数点 (非標準モード)

IEEE 754 のデフォルトの浮動小数点演算機能は「無停止」であり、アンダーフローは「段階的」です。ここでは概要を説明します。詳細については『数値計算ガイド』を参照してください。

「無停止」とは、ゼロによる除算、浮動小数点のオーバーフロー、不正演算例外などが生じても実行を停止しないことを意味します。たとえば次の式で、x はゼロ、y は正の数であるとします。

z = y / x;

デフォルトでは、z の値は +Inf になりますが、プログラムの実行は続けられます。ただし、-fnonstd オプションを使用した場合は、このコードによってプログラムが終了します (コアダンプなど)。

次に、段階的アンダーフローの動作を説明するために、次のようなコードを例として考えます。


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

ループを 1 回通ると x1 になり、2 回目で 0.1、3 回目で 0.01 と続き、やがてはマシンによって値を表現できる許容範囲の下限に到達します。次にループを実行すると、どうなるのでしょうか。

表現可能な最小の数が 1.234567e-38 であると仮定します。

次にループを実行すると、仮数部から「盗んだ」ものを指数部に「与える」ことによって数値が修正され、新しい値 1.23456e-39 になります。その次はさらに、1.2345e-40 と続いていきます。これがデフォルト動作である「段階的アンダーフロー」です。非標準モードでは、仮数部から「盗む」ことをせず、通常は単に x をゼロに設定します。

2.5 値としてのラベル

C コンパイラは、計算型 goto 文として知られる C の拡張機能を認識します。計算型 goto 文を使用すると、実行時に分岐先を判別することができます。次のように演算子 '&&' を使用して、ラベルのアドレスを取得し、void * 型のポインタに割り当てることができます。


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

あとに続く goto 文は、ptr により label1 に分岐できます。


goto *ptr;

ptr は実行時に計算されるため、ptr は有効範囲内にある任意のラベルのアドレスを取得でき、goto 文はこのアドレスに分岐することができます。

ジャンプテーブルを実装するには、計算型 goto 文を次の方法で使用します。


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

これで、次のようにインデックスを指定して配列要素を選択できます。


goto *ptrarray[i];

ラベルのアドレスは、現在の関数スコープからしか計算できません。現在の関数以外のラベルについてアドレスを取得しようとすると、予測できない結果になります。

ジャンプテーブルは switch 文と同様の働きをしますが、両者にはいくつかの相違点があり、ジャンプテーブルではプログラムフローの追跡がより困難になる可能性があります。顕著な相違点は、switch 文のジャンプ先は必ず予約語から順方向にあることです。計算型 goto 文を使用してジャンプテーブルを実装すると、順方向と反対方向の両方に分岐することができます。


#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;
}

次の例では、プログラムフローの制御にジャンプテーブルを使用しています。


#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

また、計算型 goto 文は、スレッド化されたコードのインタプリタとしても使用されます。高速ディスパッチを行うために、インタプリタ関数の範囲内にあるラベルアドレスを、スレッド化されたコードに格納することができます。

2.6 long long データ型

-xc99=none を指定してコンパイルを行う場合、Solaris Studio C コンパイラにはデータ型 long long および unsigned long long があり、これらはデータ型 long と類似しています。-m32 を使用してコンパイルすると、long long データ型には 64 ビットの情報が格納され、long には 32 ビットの情報が格納されます。-m64 を使用してコンパイルすると、long データ型には 64 ビットが格納されます。long long データ型は -Xc モードでは使用できません (警告が発行されます)。

2.6.1 long long データ型の入出力

long long データ型を出力または入力するには、変換指定子の前に ll の接頭辞を付けてください。たとえば、long long データ型を持つ変数 llvar を符号付き 10 進形式で出力するには、次のように指定します。


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

2.6.2 通常の算術変換

2 項演算子によっては、両方のオペランドの型を共通の型にするために変換することがあります。この時、結果の型も共通の型となります。この変換は通常の算術変換と呼ばれます。

2.7 Switch 文内の Case 範囲

標準 C では、switch 文内にある case のラベルに、ただ 1 つの値を関連付けることができます。Solaris Studio C では、case 範囲として知られる、一部のコンパイラに見られる拡張を許可しています。

case 範囲は、値範囲を指定し、個別の case のラベルに関連付けます。case 範囲の構文は、次のとおりです。

case low ... high:

case 範囲は、lowhigh で指定された範囲内にある各値に対して case ラベルを指定した場合とまったく同じ動作をします (low high が等しい場合は、case 範囲はただ 1 つの値を指定します)。下限と上限の値は、C 規格の要件に準拠している必要があります。つまり、これらの値は、有効な整数型の定数式であることが必要です (C 規格 6.8.4.2)。case 範囲と case ラベルは、自由に混在することができ、単一の switch 文内で複数の case 範囲を指定できます。

プログラミングの例:


enum kind { alpha, number, white, other }; 
enum kind char_class(char c); 
{     
     enum kind result;
     switch(c) {
         case 'a' ... 'z':
         case 'A' ... 'Z':
             result = alpha;
             break;
         case '0' ... '9':
             result = number;
             break;
         case ' ':
         case '\n':
         case '\t':
         case '\r':
         case '\v':
             result = white;
             break;
         default:
             result = other;
             break;
     }
     return result; }  

case ラベルに関する既存の要件に対してエラー条件を追加:

case 範囲の終点 (上限または下限) が数値リテラルである場合、省略記号 (...) の前後に半角スペースを記述し、ピリオドのいずれかが小数点として扱われることを防止してください。

次に例を示します。


 case 0...4;   // error
 case 5 ... 9; // ok

2.8 表明 (assertion)

次の書式で指定します。


#assert predicate (token-sequence)

token-sequence は、表明の名前空間 (マクロ定義用の空間から分離されている) にある述語と関連付けられます。述語は識別子トークンでなければいけません。


#assert predicate

これは述語が存在していることを表明しますが、それにトークン列を関連付けることはしません。

コンパイラは、次のような事前定義された述語をデフォルトとして提供しています (-Xc モードを除く)。


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

lint は、次のような事前定義された述語をデフォルトとして提供しています (-Xc モードを除く)。


#assert lint (on)

表明は #unassert を使用して削除できます。この場合、assert と同じ構文が使用されます。引数なしで #unassert を使用すると述語に対するすべての表明が削除され、表明を指定すればその表明だけが削除されます。

表明は、次の構文を持つ #if 文でテストすることができます。


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

たとえば次のように指定して、事前定義された述語 system をテストすることがで きます。


#if #system(unix)

これは真と評価されます。

2.9 サポートされる属性

次の属性 (__attribute__ ((keyword )) ) は、互換性のためにコンパイラにより実装されます。

2.10 警告とエラー

#error および #warning プリプロセッサディレクティブを使用すると、コンパイル時の診断を生成できます。

#error token-string

エラー診断 token-string を発行して、コンパイルを終了します。

#warning token-string

警告診断 token-string を発行してコンパイルを続行します。

2.11 プラグマ

複数行形式の前処理:


#pragma pp-tokens

各処理系が定義した処理を指定します。

次の #pragmas はコンパイルシステムに認識されます。認識されなかったプラグマは無視されます。-v オプションを使用すると、認識されなかったプラグマについて警告が出されます。

2.11.1 align

#pragma align integer (variable[, variable] )

整列プラグマで指定した変数のメモリーはデフォルト値によらず、すべて integer バイト境界に揃えられます。ただし、次の制限があります。


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

2.11.2 c99

#pragma c99("implicit" | " no%implicit")

このプラグマは、暗黙的な関数宣言の診断を制御します。c99 プラグマの値が "implicit" に設定されている場合 (引用符を使用することに注意)、コンパイラが暗黙的な関数宣言を検出すると、警告が生成されます。c99 プラグマの値が "no%implicit" に設定されている場合 (引用符を使用することに注意)、プラグマの値がリセットされるまで、コンパイラは暗黙的な関数宣言をそのまま受け入れます。

-xc99 オプションの値は、このプラグマに影響を与えます。-xc99=all の場合はプラグマが #pragma c99("implicit") に設定され、-xc99=none の場合はプラグマが #pragma c99("no%implicit") に設定されます。

デフォルトでは、このプラグマは c99=("implicit") に設定されます。

2.11.3 does_not_read_global_data

#pragma does_not_read_global_data ( funcname [, funcname])

リストに指定したルーチンが直接にも間接にも大域データを読み取らないことを表明します。この表明により、そうしたルーチンへの呼び出し前後のコードをさらに最適化することができます。具体的には、代入文やストア命令をそうした呼び出しの前後に移動することができます。

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。

2.11.4 does_not_return

#pragma does_not_return (funcname [, funcname])

指定した関数への呼び出しが復帰しないことをコンパイラに表明します。この表明により、コンパイラは、指定された関数への呼び出しが戻らないと仮定して最適化を行うことができます。たとえば、レジスタの存続期間が呼び出し元で終了する場合は、さらに最適化率を高めることができます。

指定した関数が復帰した場合は、プログラムの動作は未定義になります。次の例に示すように、このプラグマは、指定した関数をプロトタイプまたは空のパラメータリストで宣言したあとでのみ使用できます。


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

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

2.11.5 does_not_write_global_data

#pragma does_not_write_global_data (funcname [, funcname])

リストに指定したルーチンが直接にも間接にも大域データを書き込まないことを表明します。この表明により、そうしたルーチンへの呼び出し前後のコードをさらに最適化することができます。具体的には、代入文やストア命令をそうした呼び出しの前後に移動することができます。

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。大域アクセスに関する表明が真でない場合は、プログラムの動作は未定義になります。

2.11.6 error_messages

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

このエラーメッセージプラグマは、ソースプログラムの中から、C コンパイラおよび lint が発行するメッセージを制御可能にします。C コンパイラでは、警告メッセージに対してのみ有効です。C コンパイラの -w オプションを使用すると、このプラグマは無効になり、すべての警告メッセージが抑止されます。

2.11.7 fini

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

main() ルーチンを呼び出したあと、<f1> から <fn> (終了関数) までの関数を呼び出します。この種の関数は、型が void で引数はあってはいけません。プログラム制御下でプログラムが終了したとき、またはこのプログラムを含む共有オブジェクトがメモリーから除去されたときに呼び出されます。次の「初期化関数」の場合と同様、終了関数もリンクエディタによって処理された順に実行されます。

大域プログラム状態が初期化関数の影響を受ける場合には注意が必要です。たとえばシステムライブラリ初期化関数を使用したときに何が発生するかがインタフェースに明示的に規定されていないかぎり、システムライブラリ初期化関数によって変更される可能性がある errno の値などの大域状態情報をすべて取得し、復元する必要があります。

このような関数は #pragma fini 指令の中に登場するたびに、1 回呼び出されます。

2.11.8 hdrstop

#pragma hdrstop

同じプリコンパイル済みヘッダーファイルを共有すべき各ソースファイルの活性文字列 (viable prefix) の最後を識別するために、hdrstop プラグマを最後のヘッダーファイルのあとに置く必要があります。たとえば次のファイルがあるとします。


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"

ソースファイルの活性文字列は c.h で終わっているので、各ファイルの c.h のあとに #pragma hdrstop を挿入します。

#pragma hdrstop は、cc コマンドで指定されるソースファイルの活性文字列の最後にのみ使用できます。#pragma hdrstop をインクルードファイル内に指定しないでください。

2.11.9 ident

#pragma ident string

実行可能プログラムの .comment セクション内に任意の string を格納します。

2.11.10 init

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

main() を呼び出す前に、f 1 から f n までの関数 (初期化関数) を呼び出します。この種の関数は、型が void で引数はあってはいけません。実行開始時にプログラムのメモリーイメージを構成しているときに呼び出されます。共有オブジェクトの中の初期値設定子は、その共有オブジェクトをメモリー内へ持っていく動作の間、つまりプログラムの開始中、または dlopen() のような動的ロード動作中に実行されます。初期化関数の呼び出しを順序付ける方法は、それがリンクエディタによって動的または静的に処理される順序に依存します。

大域プログラム状態が終了関数の影響を受ける場合には注意が必要です。たとえばシステムライブラリを終了関数として使用したときに発生する事柄は、インタフェースに明示的に規定されていません。そういった情報が無い状態で、終了関数として使われたシステムライブラリが変更した可能性がある errno の値などの大域状態情報をすべて捕捉して、復元する必要があります。

このような関数は #pragma init 指令の中に登場するたびに、1 回呼び出されます。

2.11.11 inline

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

指定したルーチン名のインライン化を制御します。このプラグマはファイル全体に対して有効です。このプラグマでは、大域的なインライン化のみ制御可能であり、呼び出し元固有の制御を行うことはできません。

#pragma inline は、現在のファイル内にある、指定したルーチンに一致する呼び出しをインライン化するようコンパイラに指示します。この指示は、無視されることがあります。たとえば、関数本体が別のモジュールに存在していて、crossfile オプションが使用されていない場合などです。

#pragma no_inline は、現在のファイル内にある、指定したルーチンに一致する呼び出しをインライン化しないようコンパイラに指示します。

次の例に示すように、#pragma inline および #pragma no_inline は、関数がプロトタイプまたは空のパラメータリストで宣言されたあとでのみ使用できます。


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

-xldscope-xinline-xO-xcrossfile も参照してください。

2.11.12 int_to_unsigned

#pragma int_to_unsigned (funcname)

-Xt モードまたは -Xs モードで unsigned の型を返す関数が、戻り値の型 int を持つように変更します。

2.11.13 MP serial_loop

(SPARC) #pragma MP serial_loop


注 –

従来の Sun 固有の MP プラグマは推奨されず、サポートされません。代わりに、OpenMP 3.0 の仕様で規定された API をサポートします。標準命令への移植については、『OpenMP API ユーザーズガイド』を参照してください。


詳細は、「3.8.3.1 直列プラグマ」を参照してください。

2.11.14 MP serial_loop_nested

(SPARC) #pragma MP serial_loop_nested


注 –

従来の Sun 固有の MP プラグマは推奨されず、サポートされません。代わりに、OpenMP 3.0 の仕様で規定された API をサポートします。標準命令への移植情報については、『Solaris Studio OpenMP API ユーザーズガイド』を参照してください。


詳細は、「3.8.3.1 直列プラグマ」を参照してください。

2.11.15 MP taskloop

(SPARC) #pragma MP taskloop


注 –

従来の Sun 固有の MP プラグマは推奨されず、サポートされません。代わりに、OpenMP 3.0 の仕様で規定された API をサポートします。標準命令への移植については、『OpenMP API ユーザーズガイド』を参照してください。


詳細は、「3.8.3.2 並列プラグマ」を参照してください。

2.11.16 nomemorydepend

(SPARC) #pragma nomemorydepend

ループのどの繰り返しでもメモリーの依存がないと指示します。つまり、ループのどの繰り返しの中でも、同じメモリーの参照は必要がないと指示します。このプラグマを指定すると、コンパイラ (パイプライナ) はループの 1 回の繰り返しの中で、より効率的に命令をスケジュールすることができます。ループの繰り返しの中でメモリーの依存があると、プログラムの実行結果は未定義になります。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

このプラグマのスコープは、プラグマから始まり、次のブロックの始まりか現在のブロック内のプラグマに続く最初の for ループ、または現在のブロックの終わりのいずれか先に達したところで終わります。プラグマは、スコープの終端に到達した時点で最初に見つかった for ループに適用されます。

2.11.17 no_side_effect

#pragma no_side_effect(funcname[, funcname…] )

funcname には、現行の翻訳単位内の関数名を指定します。関数は、プラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。またプラグマはその関数の定義より前に指定されていなければいけません。指定した funcname に対し、プラグマはその関数に一切の副作用がないことを宣言します。つまり、funcname は渡された引数にだけ依存する結果の値を返します。funcname および呼び出された子孫については、次のことがいえます。

コンパイラはこの情報を、その関数を用いる最適化に利用することができます。関数に副作用があると、この関数を呼び出すプログラムの実行結果は未定義になります。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

2.11.18 opt

#pragma opt level (funcname[, funcname])

funcname には、現行の翻訳単位内で定義された関数名を指定します。level の値は、指定した関数に対する最適化レベルです。0、1、2、3、4、5 いずれかの最適化レベルを割り当てることができます。level を 0 に設定すると、最適化を無効にできます。関数は、プラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。プラグマは、最適化する関数の定義を処理する必要があります。

プラグマ内に指定される関数の最適化レベルは、-xmaxopt の値に下げられます。-xmaxopt=off の場合、プラグマは無視されます。

2.11.19 pack

#pragma pack(n)

#pack(n) 構造体または共用体のメンバーの境界整列を制御します。デフォルトでは、構造体または共用体のメンバーは、char 型なら 1 バイト、short 型なら 2 バイト、整数なら 4 バイトというように、その自然境界で整列されます。n を指定する場合には、すべての構造体または共用体のメンバーに対してもっとも厳密な自然境界整列となる 2 の乗数にします。ゼロは受け入れられません。

このプラグマを使用すると、構造体または共用体のメンバーの境界整列を指定できます。たとえば、#pragma pack(2) を指定すると、int、long、long long、float、double、long double、pointer が、それぞれの自然境界ではなく、2 バイト境界に整列されます。

n がプラットフォームでもっとも厳密な整列を指示する値 (-m32 の x86 では 4、—m32 の SPARC では 8、-m64 の SPARC では 32) か、それより大きな値の場合は、自然境界整列が有効になります。n が省略された場合も、メンバーは自然境界整列に戻ります。

#pragma pack(n) 指令は、その指令から次の pack 指令の間のすべての構造体または共用体の定義に適用されます。別の翻訳単位で同じ構造体または共用体に対して異なる #pragma pack の定義が行われている場合、プログラムは予期しない形でコンパイルに失敗することがあります。特に、#pragma pack(n) は、事前にコンパイルされたライブラリのインタフェースを定義するヘッダーをインクルードする前には使用しないでください。#pragma pack(n) は、プログラムコード内の境界整列を変更するすべての構造体または共用体の直前に挿入することをお勧めします。そして、その構造体の直後に #pragma pack( ) を続けてください。

#pragma pack を使用する場合、構造体または共用体自身の整列条件は、その構造体または共用体でより厳密に境界整列されるメンバーの整列条件と同一です。したがって、その構造体または共有体の任意の宣言は pack の境界整列となります。たとえば、char 型だけの struct は整列の制限はありませんが、double 型を含む struct は 8 バイトの境界上に並びます。


注 –

#pragma pack を使用して構造体または共用体のメンバーを自然境界以外の境界で整列させると、通常、これらのフィールドへのアクセスが発生した場合に SPARC 上でバスエラーが起きます。このエラーを避けるには、-xmemalign オプションも指定します。このようなプログラムをコンパイルする最適な方法については、「B.2.116 -xmemalign=abを参照してください。


2.11.20 pipeloop

#pragma pipeloop(n)

このプラグマは、引数 n に正の整定数または 0 を受け入れます。このプラグマは、ループがパイプライン化可能で、ループによる依存の最小の依存距離が n であることを指定します。距離が 0 の場合、そのループは実質的には Fortran 形式の doall ループで、ターゲットプロセッサ上でパイプライン処理するべきであることを意味します。距離が 0 より大きい場合、コンパイラは n 回だけの連続繰り返しでパイプラインを試みます。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

このプラグマのスコープは、プラグマから始まり、次のブロックの始まりか現在のブロック内のプラグマに続く最初の for ループ、または現在のブロックの終わりのいずれか先に達したところで終わります。プラグマは、スコープの終端に到達した時点で最初に見つかった for ループに適用されます。

2.11.21 rarely_called

#pragma rarely_called(funcname[, funcname])

指定した関数があまり使用されないというヒントをコンパイラに与えます。このヒントにより、コンパイラは、プロファイル収集段階に負担をかけることなく、ルーチンの呼び出し元でプロファイルフィードバック方式の最適化を行うことができます。このプラグマはヒントの提示ですので、コンパイラは、このプラグマに基づく最適化を行わないこともあります。

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。#pragma rarely_called の例を次に示します。


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

2.11.22 redefine_extname

#pragma redefine_extname old_extname new_extname

このプラグマにより、オブジェクトコード中で外部定義された old_extname の名前が new_extname に置換されます。この結果、リンク時にリンカーは new_extname だけを認識します。関数定義、初期設定子、または式のいずれかとして old_extname を最初に使用したあと、#pragma redefine_extname が指定されていると、結果は未定義になります。-Xs のモードではこのプラグマはサポートされていません。

#pragma redefine_extname を使用できる場合、コンパイラは、事前に定義されたマクロの __PRAGMA_REDEFINE_EXTNAME の定義を使用して、#pragma redefine_extname の有無に関係なく機能する移植可能なコードを作成できるようにします。

#pragma redefine_extname の目的は、関数名を変更できない場合に関数インタフェースを効率的に再定義する手段を提供することにあります。関数名を変更できない場合とは、たとえば、既存のプログラムとの互換性を保つために、ライブラリ内に、関数の古い定義と、新しいプログラムで使用する 新しい定義の両方を維持する必要がある場合です。ライブラリに新しい名前で新しい関数定義を追加した場合に、このようなことが必要になります。新旧の名前と定義が存在する関数を宣言するヘッダーファイルで #pragma redefine_extname を使用すると、その関数が使用されるときは、必ずその関数の新しい定義でリンクされるようになります。


#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.11.23 returns_new_memory

#pragma returns_new_memory (funcname[, funcname])

指定した関数の戻り値が呼び出し元のどのメモリーとも別名処理されないことを表明します。つまり、この呼び出しでは、新しいメモリー位置が返されます。この情報により、オプティマイザはポインタ値をより正確に追跡し、メモリー位置を明確化することができます。この結果、スケジューリング、パイプライン化、ループの並列化が改善されます。表明が偽の場合には、プログラムの動作は未定義になります。

次の例に示すように、このプラグマは、指定した関数をプロトタイプまたは空のパラメータリストで宣言したあとでのみ使用できます。


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

2.11.24 unknown_control_flow

#pragma unknown_control_flow (name;[, name;])

#pragma unknown_control_flow 指令は、呼び出し元のフローグラフを変更する手続きを説明するために使用されます。通常、この指令には setjmp() のような関数の宣言が伴います。Solaris のシステム上では、インクルードファイル <setjmp.h> に次の指定が含まれています。


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

setjmp() のような特性を持つほかの関数も、同様に宣言する必要があります。

原則として、この属性を認識するオプティマイザは、制御フローグラフに適切な境界を挿入できます。これによって、setjmp() を呼び出す関数内で関数呼び出しを安全に処理しながら、影響を受けないフローグラフ部分のコードを最適化することが可能になります。

指定した関数は、このプラグマの前にプロトタイプまたは空のパラメータリストで宣言する必要があります。

2.11.25 unroll

#pragma unroll (unroll_factor)

このプラグマは、引数 unroll_factor に正の整定数を受け入れます。展開係数が 1 以外の場合、指定されたループを指定の係数で展開するよう、コンパイラに指示します。コンパイラは可能なかぎり、その展開係数を使用します。展開係数が 1 の場合、ループを展開してはいけないことをコンパイラに指定します。コンパイラはこの情報をレベル 3 以上の最適化に利用します。

このプラグマのスコープは、プラグマから始まり、次のブロックの始まりか現在のブロック内のプラグマに続く最初の for ループ、または現在のブロックの終わりのいずれか先に達したところで終わります。プラグマは、スコープの終端に到達した時点で最初に見つかった for ループに適用されます。

2.11.26 warn_missing_parameter_info

#pragma [no_]warn_missing_parameter_info

#pragma warn_missing_parameter_info を指定すると、パラメータ型情報が含まれない関数宣言を持つ関数の呼び出しに対して警告が発生します。次の例を考えてみましょう。


example% 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 は、それ以前の #pragma warn_missing_parameter_info を無効にします。

デフォルトでは、#pragma no_warn_missing_parameter_infoは有効です。

2.11.27 weak

#pragma weak symbol1 [= symbol2]

弱い大域シンボルを定義します。このプラグマは主にソースファイルの中でライブラリを構築するために使用されます。リンカーは弱いシンボルを解決できなくてもエラーメッセージを表示しません。


#pragma weak symbol

これは symbol を弱いシンボルとして定義しています。symbol の定義が見つからなくても、リンカーはメッセージ等を出さなくなります。


#pragma weak symbol1 = symbol2

これは symbol1 を、symbol2 の別名である弱いシンボルと定義します。この形式のプラグマは、ソースファイルまたはそこにインクルードされたヘッダーファイルのいずれかで、symbol2 を定義した同じ変換ユニットの中にかぎり使用できます。それ以外で使用された場合は、コンパイルエラーになります。

プログラムが symbol1 を呼び出しますが、それがプログラム中で定義されていない場合には、symbol1 がリンクライブラリ中の弱いシンボルになっていると、リンカーはライブラリにある定義を使用します。しかし、プログラム自身が symbol1 を定義してある場合、プログラムでの定義が優先され、ライブラリに存在する symbol1 の弱い大域定義は使用されません。プログラムが直接 symbol2 を呼び出すと、ライブラリにある定義が使用されます。symbol2 の定義が重複して行われるとエラーになります。

2.12 事前に定義されている名前

事前定義に関する現在のリストは、cc(1) のマニュアルページを参照してください。

次の識別子は、オブジェクトに似たマクロとして事前に定義されています。

表 2–3 定義済み識別子 __STDC__

展開後  

次のモードでコンパイルする場合  

1

-Xc

0

-Xa-Xt

未定義

-Xs

__STDC__ が未定義 (#undef __STDC__) の場合、警告が発行されます。__STDC__ は、-Xs モードでは定義されていません。

2.13 errno の値の保持

-fast を使用すると、コンパイラは errno 変数を設定しない同等の最適化コードを使用して呼び出しを浮動小数点関数に自由に置き換えることができます。さらに、-fast はマクロ __MATHERR_ERRNO_DONTCARE も定義します。このマクロを使用すると、コンパイラは errno の妥当性の確認を無視できます。この結果、浮動小数点関数の呼び出しのあとに errno の値に依存するユーザーコードにより、一貫しない結果が生成される可能性があります。

この問題を解決する 1 つの方法は、-fast を使用してそのようなコードをコンパイルしないことです。ただし、-fast の最適化が必要で、コードが浮動小数点ライブラリの呼び出しのあとに正しく設定される errno の値に依存している場合は、次のオプションを使用してコンパイルしてください。

-xbuiltin=none -U__MATHERR_ERRNO_DONTCARE -xnolibmopt -xnolibmil

これを、コマンド行で -fast のあとに使用することで、コンパイラはそのようなライブラリ呼び出しを最適化しなくなり、errno が確実に正しく処理されるようになります。

2.14 拡張機能

C コンパイラは、C 言語に多数の拡張機能を実装しています。

2.14.1 _Restrict キーワード

C コンパイラは、C99 規格の restrict キーワードの同義語として _Restrict キーワードをサポートします。restrict キーワードは、-xc99=all を指定する場合にしか使用できませんが、_Restrict キーワードは、-xc99=none-xc99=all のどちらを指定する場合でも使用できます。

サポートしている C99 機能の詳細は、表 C–6 を参照してください。

2.14.2 _ _asm キーワード

__asm キーワード (先頭の 2 つの下線に注意) は、asm キーワードと同義語です。__asm キーワードではなく asm を使用し、-Xc モードでコンパイルを実行する場合、コンパイラは警告メッセージを表示します。-Xc モードで _ _asm を使用する場合、警告メッセージは表示されません。_ _asm 文の書式は次のようになります。


__asm("string");

ここで、string は有効なアセンブリ言語文です。

この文は、与えられたアセンブラテキストをアセンブリファイルに直接出力します。関数スコープではなくファイルスコープで宣言された基本的な asm 文は、「グローバル asm 文」と呼びます。ほかのコンパイラはこの文を「トップレベル」asm 文と呼びます。

グローバル asm 文は、指定された順に出力されます。つまり、互いに対して相対的な順序を維持し、周囲の関数との相対的な位置を維持します。

より高い最適化レベルでは、参照されていないと考えられる関数をコンパイラが削除することがあります。グローバル asm 内ではどの関数が参照されているかをコンパイラが把握しないので、関数が誤って削除される可能性があります。

テンプレートとオペランドの仕様を提供する、拡張された asm 文は、グローバルにできないことに注意してください。__asm および __asm__ はキーワード asm の同義語であり、互いに入れ替えて使用できます。

2.14.3 __inline__inline__

__inline および __inline__ はキーワード inline の同義語であり、互いに入れ替えて使用できます (C 規格、6.4.1 節)。

2.14.4 __builtin_constant_p()

__builtin_constant_p はコンパイラの組み込み関数です。この関数は単一の数値引数を取り、引数がコンパイル時の定数として既知である場合は 1 を返します。戻り値 0 は、その引数がコンパイル時の定数であるかどうかをコンパイラが判定できないことを意味します。この組み込み関数の標準的な使用法は、マクロ内で手動のコンパイル時最適化を行うことです。

2.14.5 __FUNCTION____PRETTY_FUNCTION__

__FUNCTION____PRETTY_FUNCTION__ は定義済みの識別子であり、字句を包含する関数の名前が含まれています。これらは、c99 の定義済みの識別子である __func__ に相当する機能です。Solaris プラットフォームでは、__FUNCTION____PRETTY_FUNCTION__ -Xs および -Xc の各モードで使用できません。

2.15 環境変数

ここでは、コンパイルや実行時環境を制御する環境変数について説明します。

2.15.1 OMP_DYNAMIC

スレッド数の動的な調整を無効または有効にします。

2.15.2 OMP_NESTED

入れ子の並列化を有効または無効にします。

2.15.3 OMP_NUM_THREADS

実行中に使用するスレッド数を設定します。

2.15.4 OMP_SCHEDULE

実行スケジュールのタイプとチャンクサイズを設定します。

2.15.5 PARALLEL

プログラムをマルチプロセッサ上で実行する場合に、使用するプロセッサ の数を指定します。対象マシンに複数のプロセッサが搭載されている場合は、スレッドは個々のプロセッサにマップできます。この例では、プログラムを実行すると、2 個のスレッドが生成され、各スレッド上でプログラムの並列化された部分が実行されるようになります。

2.15.6 SUN_PROFDATA

-xprofile=collect コマンドが実行頻度のデータを格納しているファイルの名前を制御します。

2.15.7 SUN_PROFDATA_DIR

-xprofile=collect コマンドが実行頻度データファイルを配置するディレクトリを制御します。

2.15.8 SUNW_MP_THR_IDLE

各ヘルパースレッドのタスク終了状態を制御します。 spin ns、または sleep nms と設定できます。デフォルトは sleep です。詳細については、『OpenMP API ユーザーズガイド』を参照してください。

2.15.9 TMPDIR

cc は通常 /tmp ディレクトリに一時ファイルを作成します。環境変数 TMPDIR を設定すると、別のディレクトリを指定することができます。TMPDIR が有効なディレクトリ名でない場合は、/tmp が使用されます。-xtemp オプションと環境変数 TMPDIR では、-xtemp が優先されます。

Bourne シェルの場合は次のように入力します。


$ TMPDIR=dir; export TMPDIR

C シェルの場合は次のように入力します。


% setenv TMPDIR dir

2.16 インクルードファイルを指定する方法

インクルードC コンパイラシステムに付属している標準的なヘッダーファイルのいずれかをインクルードするには、次の形式を使用します。


#include <stdio.h>

山括弧 (<>) を使用すると、プリプロセッサがが、システム内にあるヘッダーファイル用の標準的な場所でヘッダーファイルを検索するようになります。通常は /usr/include ディレクトリです。

ユーザーが自分のディレクトリに格納したヘッダーファイルの場合は、次のように書式が異なります。


#include "header.h"

書式 #include "foo.h" (二重引用符を使用) の文に対し、コンパイラは、次の順番でインクルードファイルを検索します。

  1. 現在のディレクトリ (つまり、「インクルード」するファイルを含むディレクトリ)

  2. -I オプションで命名されたディレクトリ

  3. /usr/include ディレクトリ

ヘッダーファイルがインクルードされたソースファイルと同じディレクトリにない場合は、cc コマンドで -I オプションを使用して、ヘッダーファイルが格納されているディレクトリのパスを指定してください。たとえば次のように、ソースファイル mycode.c の中で stdio.hheader.h をインクルードしたとします。


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

この header.h../defs ディレクトリに格納されている場合は、次のコマンドを実行します。次のようなコマンド行があるとします。


% cc– I../defs mycode.c

この場合、プリプロセッサが header.h を検索する順序は、最初が mycode.c を含むディレクトリ、次が ../defs ディレクトリ、最後が標準の場所となります。stdio.h については最初が ../defs、次が標準の場所となります。相違点は、現ディレクトリを検索するのは名前を二重引用符で囲んだヘッダーファイルを検索する場合だけであることです。

-I オプションは 1 つの cc コマンド行の中で複数回指定することができます。指定したディレクトリをプリプロセッサが検索する順序は、コマンド行での指定順序と同じです。cc の複数のオプションを、同じコマンド行で指定できます。


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

2.16.1 -I- オプションによる検索アルゴリズムの変更

新しい -I- オプションは、デフォルトの検索規則に対する制御をさらに強化します。この節で説明しているように、コマンド行の最初の -I- だけが有効です。-I- オプションをコマンド行に配置すると、次のような効果があります。

#include "foo.h" 形式のインクルードファイルの場合、次の順序でディレクトリを検索します。

1. -I オプションで指定されたディレクトリ内 (-I- の前後)

2. コンパイラで提供される C++ ヘッダーファイル、ANSI C ヘッダーファイル、および特殊な目的のファイルのディレクトリ。

3. /usr/include ディレクトリ内。

#include <foo.h> 形式のインクルードファイルの場合、次の順序でディレクトリを検索します。

1.-I のあとに指定した -I- オプションで指定したディレクトリ内。

2. コンパイラで提供される C++ ヘッダーファイル、ANSI C ヘッダーファイル、および特殊な目的のファイルのディレクトリ。

3. /usr/include ディレクトリ内。

次の例は、prog.c のコンパイル時に -I- を使用した結果を示しています。


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

次のコマンドでは、#include "foo.h" 形式のインクルード文のカレントディレクトリ (インクルードしているファイルのディレクトリ) のデフォルトの検索動作を示します。inc/a.h#include "c.h" 文を処理する際、プリプロセッサは、inc サブディレクトリから c.h ヘッダーファイルを読み取ります。prog.c#include "c.h" 文を処理する際、プリプロセッサは、prog.c を含むディレクトリから c.h ファイルを取り込みます。-H オプションがインクルードファイルのパスを印刷するようにコンパイラに指示していることに注意してください。


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

次のコマンドでは、-I- オプションの影響を示します。プリプロセッサは、書式 #include "foo.h" の文を処理する際に、インクルードするディレクトリを最初に検索しません。代わりに、コマンド行に配置されている順番で、-I オプションで命名されたディレクトリを検索します。inc/a.h 内にある #include "c.h" 文を処理する際、プリプロセッサは /c.h ヘッダーファイルを、inc/c.h ヘッダーファイルの代わりに取り込みます。


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

2.16.1.1 警告

コンパイラがインストールされている位置の /usr/include /lib/usr/lib を検索ディレクトリに指定しないでください。

詳細は、「B.2.37 -I[-|dir]」の節を参照してください。

2.17 フリースタンディング環境でのコンパイル

Solaris Studio C コンパイラは、標準 C ライブラリとリンクされたプログラムのコンパイルや、標準 C ライブラリおよびほかの実行時サポートライブラリが含まれる実行環境での実行をサポートします。C 標準では、そのような環境はホスト環境と呼ばれます。標準ライブラリ関数を提供しない環境は、フリースタンディング環境と呼ばれます。

コンパイルされたコードから呼び出される特定の実行時サポート関数は通常、標準 C ライブラリでのみ使用可能なため、C コンパイラはフリースタンディング環境での一般的なコンパイルをサポートしません。問題は、コンパイラによるソースコードの変換で、関数呼び出しが存在しないソースコード構造体に実行時サポート関数への呼び出しが導入される場合があることです。これらの関数は通常フリースタンディング環境で使用できません。次の例を考えてみましょう。


% cat -n lldiv.c
	 1	void
	 2	lldiv(
	 3	    long long *x,
	 4	    long long *y,
	 5	    long long *z)
	 6	{
	 7	    *z = *x / *y ;
	 8	}
% cc -c -m32 lldiv.c
% nm lldiv.o | grep " U "
 0x00000000 U __div64
% cc -c -m64 lldiv.c
% nm lldiv.o | grep " U "

この例では、ソースファイル lldiv.c がコンパイルされ、-m32 オプションを使用して 32 ビットプラットフォームで実行されると、行 7 の文の変換が、__div64 という名前の実行時サポート関数への外部参照となります。この関数は、標準 C ライブラリの 32 ビットバージョンでのみ使用できます。

同じソースファイルが -m64 オプションを使用して 64 ビットプラットフォームでコンパイルされると、コンパイラはターゲットマシンの 64 ビット算術命令セットを使用するため、標準 C ライブラリの 64 ビットバージョンで実行時サポート関数が不要になります。

一般的な事例では、フリースタンディング環境を対象にして C コンパイラを使用することはできませんが、特定のフリースタンディング環境 (つまり Solaris カーネルとデバイスドライバ) ではコードをコンパイルするためにコンパイラを使用できます (警告が生成されます)。

デバイスドライバなど、Solaris カーネルで実行されるコードは、外部関数呼び出しがカーネル内で使用可能な関数のみ参照するように記述する必要があります。これを可能にするため、次のガイドラインが推奨されます。

  1. ユーザーモードでのみ実行されるライブラリのヘッダーファイルは含めないでください。

  2. 同じ関数がカーネルに存在していることがわかっているのでない限り、標準 C ライブラリまたはほかのユーザーモードライブラリ内の関数を呼び出さないでください。

  3. 浮動小数点型または C99 複合型を使用しないでください。

  4. ランタイムサポートライブラリに関連付けられたコンパイラオプションを使用しないでください (-xprofile-xopenmp など)

    特定のコンパイラオプションに関連付けられた再配置可能なオブジェクトファイルは、cc(1) マニュアルページの FILES 節で説明されています。C コンパイラオプションに関連付けられた実行時サポートライブラリは、関連するオプションを説明している箇所に記載されています。

前述のように、ソースコードの変換の結果、コンパイラにより実行時サポート関数への呼び出しが生成されることがあります。Solaris カーネルの特定の事例では、カーネルが浮動小数点型や複合型、数学ライブラリ関数、または実行時サポートライブラリに関連付けられたコンパイラオプションを使用しないため、呼び出される実行時サポート関数のセットが一般的な事例より小さくなります。

次の表に、C コンパイラによるソースコードの変換の結果、Solaris カーネルで実行するためにコンパイルされたコードで呼び出される可能性のある実行時サポート関数を示します。この表に、ソースコードの変換で呼び出しが生成されるプラットフォーム、呼び出される関数の名前、関数呼び出しを引き起こすソース構造体またはコンパイラ機能を示します。C コンパイラをサポートする Solaris のすべてのバージョンで 64 ビットカーネルが実行されるため、64 ビットプラットフォームだけがリストに示されています。

32 ビット命令セット用にコンパイルすると、命令セットに固有の制限があるため、追加のマシン固有のサポート関数が呼び出されることがあります。

関数 

64 ビットプラットフォーム 

参照元 

__align_cpy_n

SPARC 

大きい構造体を返します。n は 1、2、4、8、または 16 です。

_memcpy

x86 

大きい構造体を返します。 

_memcpy

x86 および SPARC 

ベクトル化。 

_memmove

x86 および SPARC 

ベクトル化。 

_memset

x86 および SPARC 

ベクトル化。 

一部のバージョンのカーネルは、_memmove()_memcpy()、または _memset() を提供しませんが、ユーザーモードルーチン memmove()、memcpy()、および memset() のカーネルモードアナログは提供する点に注意してください。

追加情報については、『Writing Device Drivers』および『SPARC Compliance Definition, version 2.4』を参照してください。