非標準機能
This presentation is the property of its rightful owner.
Sponsored Links
1 / 28

非標準機能 処理系依存機能 PowerPoint PPT Presentation


  • 63 Views
  • Uploaded on
  • Presentation posted in: General

非標準機能 処理系依存機能. 内容. 非標準機能 標準化以前のソースコード 独自拡張 C99 と ISO C++ 処理系依存. 内容. 非標準機能 標準化以前のソースコード 独自拡張 C99 と ISO C++ 処理系依存. 標準化前のソースコード. C 言語 1990 年の標準化( C90 )と 1999 年の標準化( C99 )がある C++ 1998 年に ISO 標準策定( ISO C++, C++ std ). C 言語には 90 年以前に書かれたコード資産がある

Download Presentation

非標準機能 処理系依存機能

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


6073635

非標準機能処理系依存機能


6073635

内容

  • 非標準機能

    • 標準化以前のソースコード

    • 独自拡張

  • C99 と ISO C++

  • 処理系依存


6073635

内容

  • 非標準機能

    • 標準化以前のソースコード

    • 独自拡張

  • C99 と ISO C++

  • 処理系依存


6073635

標準化前のソースコード

  • C言語

    • 1990年の標準化(C90)と1999年の標準化(C99)がある

  • C++

    • 1998年にISO標準策定(ISO C++, C++ std)

  • C言語には90年以前に書かれたコード資産がある

  • Visual Studio 6.0 (コンパイラは 1997年のもの)で書かれたコードも多い

場合によっては、標準以前のコード→標準への変換が必要


6073635

関数の引数

  • 関数() と {} の間に引数の型を宣言

標準化前

C90

int function(arg1, arg2)

int arg1;

int arg2;

{

return arg1 + arg2;

}

int function(

int arg1,

int arg2)

{

return arg1 + arg2;

}

  • () 内で引数の型を宣言


For c

for 内で定義した変数(C++)

  • for の () 内で宣言した変数を、for ループの後ろで再利用可能

VC++ 6.0

ISO C++

for (int i=1; i<N; ++i)

sum += i;

for (i=1; i<N; ++i)

prod *= i;

for (int i=1; i<N; ++i)

sum += i;

for (int i=1; i<N; ++i)

prod *= i;

for (int i=1; i<N; ++i)

sum += i;

assert(i == N);

int i;

for (i=1; i<N; ++i)

sum += i;

assert(i == N);

  • for の () 内で宣言した変数は、for 内でしか使えない


6073635

std名前空間

  • .h なしのヘッダファイルも std 名前空間に入ってない

VC++ 6.0

ISO C++

#include <cstdio>

int main()

{

printf("foo\n");

}

#include <cstdio>

int main()

{

std::printf("foo\n");

}

  • .h なしのヘッダファイル中の関数は std 名前空間に入っている


6073635

内容

  • 非標準機能

    • 標準化以前のソースコード

    • 独自拡張

  • C99 と ISO C++

  • 処理系依存


6073635

独自拡張

  • たまにある誤解

    • 誤: GCC でコンパイルできれば標準

    • 正: GCCは独自拡張機能が多い

      • むしろ、標準対応率は VC++ 2005 のコンパイラが一番高い

  • GCC で C/C++ プログラムを書くときは、

  • -ansi -pedandic -std オプションを付ける

  • -ansi: C90, ISO C++(98) でコンパイル

  • -pedantic: GCC 独自拡張機能をオフにする

  • -std: -std "c++98" とかでバージョンを指定


6073635

配列のコピー代入

  • GCC では = で配列をコピーできる†

    • 標準では無理(ポインタ渡しなら可能)

char a[8], b[8]="StringB";

a = b;

  • 標準では・・・

    • memcpy を使う

char a[8], b[8]="StringB";

memcpy(a, b, 8);

†注意: 流石にこんなバグの原因になりそうな構文は、削除された模様。最新のGCCでは使えない。


Switch case

switch case で範囲指定

  • GCC では、case に範囲を指定できる

switch (n) {

case 0 ... 3 : /* do something */break;

・・・

  • 標準では・・・

    • case を複数並べる

switch (n) {

case 0:

case 1:

case 2:

case 3:

/* do something */

break;

・・・


6073635

関数内で関数定義

  • GCC では、関数内に関数を書ける

void func(double x[], int num)

{

int inner(double xd) {

return 1 / (1 - xd);

}

for (int i=0 ; i<num ; i++) {

printf("%d\n", inner(x[i]));

}

}

  • 標準では同様の機能なし


6073635

内容

  • 非標準機能

    • 標準化以前のソースコード

    • 独自拡張

  • C99 と ISO C++

  • 処理系依存


C c99

C++とC99

  • C++とC99には互換性がない

C言語

C90

C99

互換性なし

上位互換あり

C++

ISO C++ (98)

  • C99 も標準とはいえ・・・

    • C++ との非互換が不評

    • 対応しているのは GCC くらい

      • 元々、GCC の独自拡張機能が C99 標準として採用された


C c991

C++とC99共通の機能

  • // コメント

  • inline キーワード

  • 暗黙の関数宣言廃止

C90

C99, C++

/* 戻り値・引数の型を省略

* すると int になる */

func(x1, x2)

{

return x1 * x2

}

// 型の省略禁止

// inline キーワード追加

inline

int func(int x1, int x2)

{

return x1 * x2

}


6073635

可変長引数マクロ

  • C99 では、可変長引数を持つマクロを定義できる

#define dbg(fmt, ...) \

printf("debug:" fmt, __VA_ARGS__)

  • C++ では・・・

    • 引数を持つマクロ自体非推奨

    • 代わりに inline 関数を使う

inline void dbg(char* fmt, ...)

{

va_list args;

va_start (args, format);

vfprintf (stdout, "debug:"format, args);

va_end (args);

}


6073635

可変長配列

  • C99 では、変数で配列の長さを指定できる

void func(int n)

{

double x[n];

・・・

  • C++ では・・・

    • 配列ではなく、vector クラスを使う

#include <vector>

using std::vector;

void func(int n)

{

vector<double> x = new vector<double>(n);

・・・


6073635

初期化子

  • C99 では、以下のような構文で構造体の初期化可能

struct point {

int x;

int y;

};

struct point p = { .x = 1, .y = 2};

  • C++ では・・・

    • コンストラクタを使う

struct Point {

int x;

int y;

Point(int xx, int yy) { x = xx; y = yy; }

};

Point p = new Point(1, 2);


Restrict

restrict ポインタ

  • 二つのポインタが同じ箇所を指していないことを明示することでコンパイラの最適化を促す

void sumup(int n,

int * restrict array1,

int * restrict array2)

{

for (int i = 0; i < n; i++)array1[i] += array2[i];

}

  • こういう処理をするとき、array1 != array2 が保証されている場合にのみ使える命令があったりする

  • 残念ながら C++ には同様の機能なし


6073635

内容

  • 非標準機能

    • 標準化以前のソースコード

    • 独自拡張

  • C99 と ISO C++

  • 処理系依存


6073635

処理系依存

  • C/C++ の規格上、コンパイラごとに変えてもいい部分が多々ある

    • オペランドの評価順

    • short, int, long のサイズ

    • 構造体のパッキング


6073635

オペランドの評価順

  • a+b の a を先に評価するか b を先に評価するかは決められていない

int func(int n) {

printf("%d ", n); return n;

}

int x = func(1) + func(2);

  • 「1 2」と表示されるか「2 1」と表示されるかは未定義

  • ちゃんと分けて書くべき

int a = func(1);

int b = func(2);

int x = a + b;


Short int long

short, int, long のサイズ

  • 規格上では、以下の不等号のみが定められている

    • sizeof(short) ≦ sizeof(int) ≦ sizeof(long)

  • short, int, long のサイズ

    • 16, 16, 32 ・・・ OK

    • 16, 32, 32 ・・・ OK

    • 16, 32, 64 ・・・ OK

    • 16, 64, 64 ・・・ OK

    • 32, 32, 16 ・・・ これは駄目

  • サイズ固定の整数を使いたければ・・・

    • int32 などを使う(コンパイラごとに異なる)

    • C99 には stdint.h という、サイズ固定の整数を定義したヘッダがある


6073635

構造体のパッキング(1)

  • 構造体のメンバとメンバの間には隙間が空くことがある

    • (例えば32ビットCPUでは)4バイト間隔でメンバがならんでいると効率よくアクセス可能

    • 隙間の空け方は規格で定められていない

struct {

char c1;

char c2;

} x;

long offset = &(x.c2) - &x;

  • offset の値は処理系ごとに異なる


6073635

構造体のパッキング(2)

struct {

char c1;

char c2;

} x;

以下の3つとも規格上 OK

x

x

x

c1

c1

c1

c2

c2

c2

  • コンパイラによっては、パッキング(メンバの並べ方)を指定可能(#pragma pack など。コンパイラごとに異なる)


6073635

コンパイラごとに処理を変える

  • コンパイラを判定

    • ifdef で各コンパイラ特有のシンボルを確認

#ifdef __GNUC__

// GCC 用コード

#endif

#ifdef __BORLANDC__

// Borland C++ 及び C++Builder 用コード

#endif

#ifdef __WATCOMC__

// Watcom C/C++ 用コード

#endif

#ifdef _MSC_VER

// Visual C++ 用コード

#endif


Pragma

pragma

  • #pragma プリプロセッサ

    • コンパイラ依存の指示を出す

    • #pragma でできること / 書き方はコンパイラごとに異なる

    • 対応していない #pragma は無視する

(例) 構造体のパッキングを指定

#pragma pack(push,1)

struct {

char c1;

char c2;

} x;

  • 右の図のようになることが保証される

  • (この書き方は Visual C++ のもの)

x

c1

c2


6073635

参考URL

  • GCC 独自拡張

    • http://www-cms.phys.s.u-tokyo.ac.jp/~naoki/CIPINTRO/gccextend.html

  • C99

    • http://seclan.dll.jp/c99d/c99d00.htm

  • VC++ 6.0 の癖

    • http://www.fides.dti.ne.jp/~oka-t/vc-mfc.html


  • Login