第11回 GCC2.95から追加変更のあったオプションの補足と検証

岸 哲夫

 本連載も10回をすぎた.連載開始当初は一般的だったGCC2.95も少数派になっていることだろう.新旧のバージョンを比較すると,機能が大きく変化しているため,本連載で扱うバージョンをGCC3.3に改めることにする(ただし,今回のみGCC3.3の環境構築が間に合わなかったので,検証はGCC3.2.2で行う).そこで,今回から2回の予定で,GCC2.95から追加変更のあったオプションの補足と検証を行うことにする. (筆者)

space

 今後,本連載で扱う予定の項目を以下に記します.

・GCC2.95から追加変更のあったオプションの補足と検証
・GCC2.95から追加変更のあった,その他言語仕様の補足と検証
・GDBを使用するためのデバッグオプションについての検証
・GCCが使用している標準ライブラリの使用法と検証
・GCCのプログラミング
・GTK,GNOME,KDEなどを使ったGUIプログラミング

 その後,C++言語やProlog,Javaなども含めたプログラミング言語やスクリプト言語,またデータベースといった多種にわたるGNUツールに関して,解説および検証を行っていく予定です.

 さて,GCC3.2.2になり,オプションの種類と使用法が変わってきました.それを2回の予定で説明・検証していきます.

C言語の方言を扱うオプション

■-ansi

 ANSI規格に沿ったCプログラムをサポートします.つまり,ISO C89規格を採用しています.ここで,C99規格やGCCの拡張機能を使用するとエラーになります(リスト1).

〔リスト1〕C99規格でエラーになる例test141.c)
/*
 *可変個数の引数を持つマクロの例(C99規格)
 */
#include <stdio.h>
#define M_debug(format, ...)	printf("debug:" format, __VA_ARGS__)
main()
{
	int	x01	=	100;
	int	x02	=	200;
	M_debug("x01=%d\n",x01);
	M_debug("(%d,%d)\n",x01,x02);
	M_debug("(%d,%d,%d行目)\n",x01,x02,__LINE__ );
}

 コンパイルした結果を以下に示します.

  $ gcc -ansi -pedantic test141.c -o test141
  $ test141.c:5:25: 警告: 無名可変引数マクロは C99 で採り入れられました

 この場合,ワーニングエラーにはなりますが,実行は可能です.アセンブラソース(リスト2)も正しく展開されています.

〔リスト2〕生成されたアセンブラソースtest141_1.s)
	.file	"test141.c"
	.section	.rodata
.LC0:
	.string	"debug:x01=%d\n"
.LC1:
	.string	"debug:(%d,%d)\n"
.LC2:
	.string	"debug:(%d,%d,%d\271\324\314\334)\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$100, -4(%ebp)
	movl		$200, -8(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	subl		$4, %esp
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC1
	call		printf
	addl		$16, %esp
	pushl	$12
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC2
	call		printf
	addl		$16, %esp
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

 以下に実行結果を示します.

  $ ./test141
  debug:x01=100
  debug:(100,200)
  debug:(100,200,12行目)
  $

 問題なく動作しました.また,デフォルトでコンパイルしても同じ実行結果になりました.

  $ gcc test141.c -o test141
  $ ./test141
  debug:x01=100
  debug:(100,200)
  debug:(100,200,12行目)
  $

■-std=

・指定するパラメータの値

  c89
  iso9899:1990

 上の値を=の後に指定するとISO C89規格でコンパイルされます.現在は-ansiを指定したことと同義になります.

 先に使用したソース(リスト1)をコンパイルすると,結果は以下のようになります.

  $ gcc -std=c89 -pedantic test141.c -o test141
  test141.c:5:25: 警告: 無名可変引数マクロは C99 で採り入れられました
  $ gcc -std=iso9899:1990 -pedantic test141.c -o test141
  test141.c:5:25: 警告: 無名可変引数マクロは C99 で採り入れられました
  $

・指定するパラメータの値

  c99
  c9x
  iso9899:1999
  iso9899:199x

 上の値を=の後に指定すると,ISO C99規格でコンパイルされます.前述したとおり完全にサポートしているわけではありません.

 リスト1のソースをコンパイルすると,結果は以下のようになります.

  $ gcc -std=c99 test141.c -o test141
  test141.c:7: 警告: 戻り値の型をデフォルトの `int' とします
  $ gcc -std=c9x test141.c -o test141
  test141.c:7: 警告: 戻り値の型をデフォルトの `int' とします
  $ gcc -std=iso9899:1999 test141.c -o test141
  test141.c:7: 警告: 戻り値の型をデフォルトの `int' とします
  $ gcc -std=iso9899:199x test141.c -o test141
  test141.c:7: 警告: 戻り値の型をデフォルトの `int' とします
  $

 test141.cでは戻り値を明示的に指定していませんが,C99規格では許されません.そこでワーニングエラーを出します.

 リスト3のアセンブラソースを見るとわかるように,デフォルトの戻り値を0として生成しています.

〔リスト3〕C99規格で生成されたアセンブラソースtest141_2.s)
	.file	"test141.c"
	.section	.rodata
.LC0:
	.string	"debug:x01=%d\n"
.LC1:
	.string	"debug:(%d,%d)\n"
.LC2:
	.string	"debug:(%d,%d,%d\271\324\314\334)\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$100, -4(%ebp)
	movl		$200, -8(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	subl		$4, %esp
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC1
	call		printf
	addl		$16, %esp
	pushl	$12
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC2
	call		printf
	addl		$16, %esp
	movl		$0, %eax
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

・指定するパラメータの値

  gnu89

 上の値を=の後に指定すると,ISO C89規格とGCC拡張仕様の組み合わせ,かつC99規格を含む言語仕様となります.これが現バージョンのデフォルトです.

 リスト1のソースをコンパイルすると,結果は次のようになります.

  $ gcc -std=gnu89 test141.c -S
  $ cp test141.s test141_3.s
  $

 リスト4のアセンブラソース,およびコンパイル結果を見ると-ansiでもC99規格でもないことがわかります.これがGCC独自の言語仕様です.

〔リスト4〕デフォルトの言語仕様で生成されたアセンブラソースtest141_3.s)
	.file	"test141.c"
	.section	.rodata
.LC0:
	.string	"debug:x01=%d\n"
.LC1:
	.string	"debug:(%d,%d)\n"
.LC2:
	.string	"debug:(%d,%d,%d\271\324\314\334)\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$100, -4(%ebp)
	movl		$200, -8(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	subl		$4, %esp
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC1
	call		printf
	addl		$16, %esp
	pushl	$12
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC2
	call		printf
	addl		$16, %esp
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

・指定するパラメータの値

  gnu99
  gnu9x

 上の値を=の後に指定すると,ISO C99規格とGCC拡張仕様の組み合わせでコンパイルされます.将来は,これがデフォルトになります.

 リスト1のソースをコンパイルすると,結果は以下のようになります.

  $ gcc -std=gnu99 test141.c -S
  test141.c:7: 警告: 戻り値の型をデフォルトの `int' とします
  $ gcc -std=gnu9x test141.c -S
  test141.c:7: 警告: 戻り値の型をデフォルトの `int' とします
  $ cp test141.s test141_4.s
  $

 test141.cでは戻り値を明示的に指定していませんが,C99規格では許されません.そこでワーニングエラーを出します.

 リスト5のアセンブラソースを見るとわかるように,デフォルトの戻り値を0として生成しています.つまり,C99規格を使用してコンパイルしています.

〔リスト5〕C99規格で生成されたアセンブラソースtest141_4.s)
	.file	"test141.c"
	.section	.rodata
.LC0:
	.string	"debug:x01=%d\n"
.LC1:
	.string	"debug:(%d,%d)\n"
.LC2:
	.string	"debug:(%d,%d,%d\271\324\314\334)\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$100, -4(%ebp)
	movl		$200, -8(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	subl		$4, %esp
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC1
	call		printf
	addl		$16, %esp
	pushl	$12
	pushl	-8(%ebp)
	pushl	-4(%ebp)
	pushl	$.LC2
	call		printf
	addl		$16, %esp
	movl		$0, %eax
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

 では,リスト1のソースにGCC拡張機能を含む処理を追加して(リスト6),コンパイルしてみます.

〔リスト6〕C99規格およびGCC拡張機能を含む例test142.c)
/*
 *可変個数の引数を持つマクロの例(C99規格)
 *typeofでマクロを作る例(GCC拡張規格)
 */
#include <stdio.h>
#define M_debug(format, ...)printf("debug:" format, __VA_ARGS__)
#define pointer(T)  typeof(T *)
#define array(T, N) typeof(T [N])
main()
{
	int ix;
	int	x01	=	100;
	int	x02	=	200;
/*	*/
	array (pointer (char), 10) char_p;
	array (pointer (long), 10) long_p;
/*	*/
	M_debug("x01=%d\n",x01);
	M_debug("(%d,%d)\n",x01,x02);
	M_debug("(%d,%d,%d行目)\n",x01,x02,__LINE__ );
/*	*/
	for (ix=0;ix<10;ix++)
	{
		char_p[ix] = (char	*)'a'+ix;
		long_p[ix] = (long	*)(ix * 1000000L);
	}
	for (ix=0;ix<10;ix++)
	{
		printf("char_p[%d] = %d\n",ix,char_p[ix]);
	}
	for (ix=0;ix<10;ix++)
	{
		printf("long_p=[%d] = %d\n",ix,long_p[ix]);
	}
}

  $ gcc -std=gnu9x test142.c -o test142
  test142.c:10: 警告: 戻り値の型をデフォルトの `int' とします
  $ gcc -std=gnu9x test142.c -S
  test142.c:10: 警告: 戻り値の型をデフォルトの `int' とします
  $

 両方の言語仕様を含むソースでも,問題なくコンパイルできます.では,実行してみましょう.

  $ ./test142
  debug:x01=100
  debug:(100,200)
  debug:(100,200,20行目)
  char_p[0] = 97
  char_p[1] = 98
  char_p[2] = 99
  char_p[3] = 100
  char_p[4] = 101
  char_p[5] = 102
  char_p[6] = 103
  char_p[7] = 104
  char_p[8] = 105
  char_p[9] = 106
  long_p=[0] = 0
  long_p=[1] = 1000000
  long_p=[2] = 2000000
  long_p=[3] = 3000000
  long_p=[4] = 4000000
  long_p=[5] = 5000000
  long_p=[6] = 6000000
  long_p=[7] = 7000000
  long_p=[8] = 8000000
  long_p=[9] = 9000000

 結果とアセンブラソース(リスト7)を見ればわかるように,どちらの機能も生きています.

〔リスト7〕生成されたアセンブラソースtest142.s)
	.file	"test142.c"
	.section	.rodata
.LC0:
	.string	"debug:x01=%d\n"
.LC1:
	.string	"debug:(%d,%d)\n"
.LC2:
	.string	"debug:(%d,%d,%d\271\324\314\334)\n"
.LC3:
	.string	"char_p[%d] = %d\n"
.LC4:
	.string	"long_p=[%d] = %d\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$120, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$100, -16(%ebp)
	movl		$200, -20(%ebp)
	subl		$8, %esp
	pushl	-16(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	subl		$4, %esp
	pushl	-20(%ebp)
	pushl	-16(%ebp)
	pushl	$.LC1
	call		printf
	addl		$16, %esp
	pushl	$20
	pushl	-20(%ebp)
	pushl	-16(%ebp)
	pushl	$.LC2
	call		printf
	addl		$16, %esp
	movl		$0, -12(%ebp)
.L2:
	cmpl		$9, -12(%ebp)
	jle	.L5
	jmp	.L3
.L5:
	movl		-12(%ebp), %edx
	movl		-12(%ebp), %eax
	addl		$97, %eax
	movl		%eax, -72(%ebp,%edx,4)
	movl		-12(%ebp), %ecx
	movl		-12(%ebp), %edx
	movl		%edx, %eax
	sall		$2, %eax
	addl		%edx, %eax
	leal		0(,%eax,4), %edx
	addl		%edx, %eax
	leal		0(,%eax,4), %edx
	addl		%edx, %eax
	leal		0(,%eax,4), %edx
	addl		%edx, %eax
	leal		0(,%eax,4), %edx
	addl		%edx, %eax
	leal		0(,%eax,4), %edx
	addl		%edx, %eax
	sall		$6, %eax
	movl		%eax, -120(%ebp,%ecx,4)
	leal		-12(%ebp), %eax
	incl		(%eax)
	jmp	.L2
.L3:
	movl		$0, -12(%ebp)
.L6:
	cmpl		$9, -12(%ebp)
	jle	.L9
	jmp	.L7
.L9:
	subl		$4, %esp
	movl		-12(%ebp), %eax
	pushl	-72(%ebp,%eax,4)
	pushl	-12(%ebp)
	pushl	$.LC3
	call		printf
	addl		$16, %esp
	leal		-12(%ebp), %eax
	incl		(%eax)
	jmp	.L6
.L7:
	movl		$0, -12(%ebp)
.L10:
	cmpl		$9, -12(%ebp)
	jle	.L13
	jmp	.L11
.L13:
	subl		$4, %esp
	movl		-12(%ebp), %eax
	pushl	-120(%ebp,%eax,4)
	pushl	-12(%ebp)
	pushl	$.LC4
	call		printf
	addl		$16, %esp
	leal		-12(%ebp), %eax
	incl		(%eax)
	jmp	.L10
.L11:
	movl		$0, %eax
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

■-aux-info filename

 ヘッダファイル中のものを含むすべてのプロトタイプ(リスト8)を出力します.

〔リスト8〕生成されたリストtest142.txt)
/* compiled from: . */
/* /usr/include/libio.h:402:NC */ extern int __underflow (_IO_FILE *);
/* /usr/include/libio.h:403:NC */ extern int __uflow (_IO_FILE *);
/* /usr/include/libio.h:404:NC */ extern int __overflow (_IO_FILE *, int);
/* /usr/include/libio.h:405:NC */ extern wint_t __wunderflow (_IO_FILE *);
/* /usr/include/libio.h:406:NC */ extern wint_t __wuflow (_IO_FILE *);
/* /usr/include/libio.h:407:NC */ extern wint_t __woverflow (_IO_FILE *, wint_t);
/* /usr/include/libio.h:432:NC */ extern int _IO_getc (_IO_FILE *);
/* /usr/include/libio.h:433:NC */ extern int _IO_putc (int, _IO_FILE *);
/* /usr/include/libio.h:434:NC */ extern int _IO_feof (_IO_FILE *);
/* /usr/include/libio.h:435:NC */ extern int _IO_ferror (_IO_FILE *);
/* /usr/include/libio.h:437:NC */ extern int _IO_peekc_locked (_IO_FILE *);
/* /usr/include/libio.h:443:NC */ extern void _IO_flockfile (_IO_FILE *);
/* /usr/include/libio.h:444:NC */ extern void _IO_funlockfile (_IO_FILE *);
/* /usr/include/libio.h:445:NC */ extern int _IO_ftrylockfile (_IO_FILE *);
/* /usr/include/libio.h:463:NC */ extern int _IO_vfscanf (_IO_FILE *, const char *, __gnuc_va_list, int *);
/* /usr/include/libio.h:465:NC */ extern int _IO_vfprintf (_IO_FILE *, const char *, __gnuc_va_list);
/* /usr/include/libio.h:466:NC */ extern __ssize_t _IO_padn (_IO_FILE *, int, __ssize_t);
/* /usr/include/libio.h:467:NC */ extern size_t _IO_sgetn (_IO_FILE *, void *, size_t);
/* /usr/include/libio.h:469:NC */ extern __off64_t _IO_seekoff (_IO_FILE *, __off64_t, int, int);
/* /usr/include/libio.h:470:NC */ extern __off64_t _IO_seekpos (_IO_FILE *, __off64_t, int);
/* /usr/include/libio.h:472:NC */ extern void _IO_free_backup_area (_IO_FILE *);
/* /usr/include/stdio.h:154:NC */ extern int remove (const char *);
/* /usr/include/stdio.h:156:NC */ extern int rename (const char *, const char *);
/* /usr/include/stdio.h:163:NC */ extern FILE *tmpfile (void);
/* /usr/include/stdio.h:173:NC */ extern char *tmpnam (char *);
/* /usr/include/stdio.h:183:NC */ extern char *tmpnam_r (char *);
/* /usr/include/stdio.h:196:NC */ extern char *tempnam (const char *, const char *);
/* /usr/include/stdio.h:202:NC */ extern int fclose (FILE *);
/* /usr/include/stdio.h:204:NC */ extern int fflush (FILE *);
/* /usr/include/stdio.h:209:NC */ extern int fflush_unlocked (FILE *);
/* /usr/include/stdio.h:222:NC */ extern FILE *fopen (const char *, const char *);
/* /usr/include/stdio.h:226:NC */ extern FILE *freopen (const char *, const char *, FILE *);
/* /usr/include/stdio.h:252:NC */ extern FILE *fdopen (int, const char *);
/* /usr/include/stdio.h:276:NC */ extern void setbuf (FILE *, char *);
/* /usr/include/stdio.h:281:NC */ extern int setvbuf (FILE *, char *, int, size_t);
/* /usr/include/stdio.h:288:NC */ extern void setbuffer (FILE *, char *, size_t);
/* /usr/include/stdio.h:291:NC */ extern void setlinebuf (FILE *);
/* /usr/include/stdio.h:298:NC */ extern int fprintf (FILE *, const char *, ...);
/* /usr/include/stdio.h:300:NC */ extern int printf (const char *, ...);
/* /usr/include/stdio.h:303:NC */ extern int sprintf (char *, const char *, ...);
/* /usr/include/stdio.h:307:NC */ extern int vfprintf (FILE *, const char *, __gnuc_va_list);
/* /usr/include/stdio.h:310:NC */ extern int vprintf (const char *, __gnuc_va_list);
/* /usr/include/stdio.h:313:NC */ extern int vsprintf (char *, const char *, __gnuc_va_list);
/* /usr/include/stdio.h:321:NC */ extern int snprintf (char *, size_t, const char *, ...);
/* /usr/include/stdio.h:325:NC */ extern int vsnprintf (char *, size_t, const char *, __gnuc_va_list);
/* /usr/include/stdio.h:354:NC */ extern int fscanf (FILE *, const char *, ...);
/* /usr/include/stdio.h:356:NC */ extern int scanf (const char *, ...);
/* /usr/include/stdio.h:359:NC */ extern int sscanf (const char *, const char *, ...);
/* /usr/include/stdio.h:383:NC */ extern int fgetc (FILE *);
/* /usr/include/stdio.h:384:NC */ extern int getc (FILE *);
/* /usr/include/stdio.h:387:NC */ extern int getchar (void);
/* /usr/include/stdio.h:396:NC */ extern int getc_unlocked (FILE *);
/* /usr/include/stdio.h:397:NC */ extern int getchar_unlocked (void);
/* /usr/include/stdio.h:402:NC */ extern int fgetc_unlocked (FILE *);
/* /usr/include/stdio.h:408:NC */ extern int fputc (int, FILE *);
/* /usr/include/stdio.h:409:NC */ extern int putc (int, FILE *);
/* /usr/include/stdio.h:412:NC */ extern int putchar (int);
/* /usr/include/stdio.h:421:NC */ extern int fputc_unlocked (int, FILE *);
/* /usr/include/stdio.h:426:NC */ extern int putc_unlocked (int, FILE *);
/* /usr/include/stdio.h:427:NC */ extern int putchar_unlocked (int);
/* /usr/include/stdio.h:433:NC */ extern int getw (FILE *);
/* /usr/include/stdio.h:436:NC */ extern int putw (int, FILE *);
/* /usr/include/stdio.h:443:NC */ extern char *fgets (char *, int, FILE *);
/* /usr/include/stdio.h:447:NC */ extern char *gets (char *);
/* /usr/include/stdio.h:480:NC */ extern int fputs (const char *, FILE *);
/* /usr/include/stdio.h:483:NC */ extern int puts (const char *);
/* /usr/include/stdio.h:487:NC */ extern int ungetc (int, FILE *);
/* /usr/include/stdio.h:492:NC */ extern size_t fread (void *, size_t, size_t, FILE *);
/* /usr/include/stdio.h:495:NC */ extern size_t fwrite (const void *, size_t, size_t, FILE *);
/* /usr/include/stdio.h:507:NC */ extern size_t fread_unlocked (void *, size_t, size_t, FILE *);
/* /usr/include/stdio.h:509:NC */ extern size_t fwrite_unlocked (const void *, size_t, size_t, FILE *);
/* /usr/include/stdio.h:515:NC */ extern int fseek (FILE *, long int, int);
/* /usr/include/stdio.h:517:NC */ extern long int ftell (FILE *);
/* /usr/include/stdio.h:519:NC */ extern void rewind (FILE *);
/* /usr/include/stdio.h:550:NC */ extern int fgetpos (FILE *, fpos_t *);
/* /usr/include/stdio.h:552:NC */ extern int fsetpos (FILE *, const fpos_t *);
/* /usr/include/stdio.h:577:NC */ extern void clearerr (FILE *);
/* /usr/include/stdio.h:579:NC */ extern int feof (FILE *);
/* /usr/include/stdio.h:581:NC */ extern int ferror (FILE *);
/* /usr/include/stdio.h:586:NC */ extern void clearerr_unlocked (FILE *);
/* /usr/include/stdio.h:587:NC */ extern int feof_unlocked (FILE *);
/* /usr/include/stdio.h:588:NC */ extern int ferror_unlocked (FILE *);
/* /usr/include/stdio.h:594:NC */ extern void perror (const char *);
/* /usr/include/stdio.h:606:NC */ extern int fileno (FILE *);
/* /usr/include/stdio.h:611:NC */ extern int fileno_unlocked (FILE *);
/* /usr/include/stdio.h:618:NC */ extern FILE *popen (const char *, const char *);
/* /usr/include/stdio.h:621:NC */ extern int pclose (FILE *);
/* /usr/include/stdio.h:627:NC */ extern char *ctermid (char *);
/* /usr/include/stdio.h:655:NC */ extern void flockfile (FILE *);
/* /usr/include/stdio.h:659:NC */ extern int ftrylockfile (FILE *);
/* /usr/include/stdio.h:662:NC */ extern void funlockfile (FILE *);
/* test142.c:10:OF */ extern int main (void); /* () */

  $ gcc test142.c -aux-info test142.txt

■-fno-builtin,-fno-builtin-function

 ライブラリ関数のうち,abort,abs,alloca,cos,exit,fabs,ffs,labs,memcmp,memcpy,sin,sqrt,strcmp,strcpy,strlenは効率を良くするために,組み込み関数としてコンパイルされることがあります.

 その場合,デバッガを使用する際に意図しないふるまいをしたり,ライブラリ関数の処理自体が意図しないふるまいをすることがあります.それを防止するために「組み込みにしない」設定ができます.-fno-builtinは組み込み関数を,いっさい使用しません.

 なお,以下に示すtest143.c(リスト9)とtest144.cは名前が違う同一のソースです.

〔リスト9〕組み込み関数を含む例test143.c)
/*
 *組み込み関数について
 */
#include <stdlib.h>
#include <stdio.h>
main()
{
	int	a;
	a	=	abs(-5);
	printf("%d\n",a);
}

  $ gcc -fno-builtin test143.c -S
  $ gcc test144.c -S

 アセンブラソースを見ると,test143.s(リスト10)では,call absとなっていますが,test144.s(リスト11)では組み込み関数を呼び出しているようです.

〔リスト10〕test143.cから生成されたアセンブラソースtest143.s)
	.file	"test143.c"
	.section	.rodata
.LC0:
	.string	"%d\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	subl		$12, %esp
	pushl	$-5
	call		abs
	addl		$16, %esp
	movl		%eax, -4(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

〔リスト11〕test144.cから生成されたアセンブラソースtest144.s)
		.file	"test144.c"
	.section	.rodata
.LC0:
	.string	"%d\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$5, -4(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

 なお,-fno-builtin-functionというオプションもありますが,現バージョンでは何もしないことになっています.

 以下に示すtest145.cとtest146.cは名前が違う同一のソースで,test143.cと同じです.

  $ gcc -fno-builtin-function test145.c -S
  $ gcc -fbuiltin-function test146.c -S

 リスト12およびリスト13を見ればわかるように,どちらを指定しても組み込み関数を呼び出しています.

〔リスト12〕test145.cから生成されたアセンブラソースtest145.s)
	.file	"test145.c"
	.section	.rodata
.LC0:
	.string	"%d\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$5, -4(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

〔リスト13〕test146.cから生成されたアセンブラソースtest146.s)
	.file	"test146.c"
	.section	.rodata
.LC0:
	.string	"%d\n"
	.text
	.align 2
.globl main
	.type	main,@function
main:
	pushl	%ebp
	movl		%esp, %ebp
	subl		$8, %esp
	andl		$-16, %esp
	movl		$0, %eax
	subl		%eax, %esp
	movl		$5, -4(%ebp)
	subl		$8, %esp
	pushl	-4(%ebp)
	pushl	$.LC0
	call		printf
	addl		$16, %esp
	leave
	ret
.Lfe1:
	.size	main,.Lfe1-main
	.ident	"GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"

 それは,リスト14リスト15に示すシンボルリストでも確認できます.test143の場合,関数abs()は標準ライブラリ内のものをリンクしています.

〔リスト14〕test143.cから生成されたシンボルリストtest143nm.txt)
080493ec D _DYNAMIC
080494c8 D _GLOBAL_OFFSET_TABLE_
080483d4 R _IO_stdin_used
         w _Jv_RegisterClasses
080494b8 d __CTOR_END__
080494b4 d __CTOR_LIST__
080494c0 d __DTOR_END__
080494bc d __DTOR_LIST__
080493e8 d __EH_FRAME_BEGIN__
080493e8 d __FRAME_END__
080494c4 d __JCR_END__
080494c4 d __JCR_LIST__
080494e4 A __bss_start
080493dc D __data_start
08048390 t __do_global_ctors_aux
080482f0 t __do_global_dtors_aux
080493e0 d __dso_handle
         w __gmon_start__
         U __libc_start_main@@GLIBC_2.0
080494e4 A _edata
080494e8 A _end
080483b4 T _fini
080483d0 R _fp_hw
08048250 T _init
080482a8 T _start
         U abs@@GLIBC_2.0
080482cc t call_gmon_start
080494e4 b completed.1
080493dc W data_start
0804832c t frame_dummy
08048358 T main
080493e4 d p.0
         U printf@@GLIBC_2.0

〔リスト15〕test144.cから生成されたシンボルリストtest144nm.txt)
080493b0 D _DYNAMIC
0804948c D _GLOBAL_OFFSET_TABLE_
08048398 R _IO_stdin_used
         w _Jv_RegisterClasses
0804947c d __CTOR_END__
08049478 d __CTOR_LIST__
08049484 d __DTOR_END__
08049480 d __DTOR_LIST__
080493ac d __EH_FRAME_BEGIN__
080493ac d __FRAME_END__
08049488 d __JCR_END__
08049488 d __JCR_LIST__
080494a4 A __bss_start
080493a0 D __data_start
08048354 t __do_global_ctors_aux
080482c0 t __do_global_dtors_aux
080493a4 d __dso_handle
         w __gmon_start__
         U __libc_start_main@@GLIBC_2.0
080494a4 A _edata
080494a8 A _end
08048378 T _fini
08048394 R _fp_hw
08048230 T _init
08048278 T _start
0804829c t call_gmon_start
080494a4 b completed.1
080493a0 W data_start
080482fc t frame_dummy
08048328 T main
080493a8 d p.0
         U printf@@GLIBC_2.0

■-no-integrated-cpp

 GCCのサブプログラムには,cpp,cc1,as,ldがあります.そして,-Bオプションの指定でサブプログラムがどこにあるかを指定できます.つまり,指定の方法によっては標準でないcppを内部で実行することが可能になります.このオプションを指定すると,その機能を無視して標準のcppを使用します.なお,このオプションは将来も存続するかどうか不明だそうです.

 標準でないcppを使う場合には,インストール時のカスタマイズで指定したほうが混乱しないでしょう.


NEW記事内インデックス    連載インデックスはこちら   Interfaceのトップ
◆C言語の方言を扱うオプション
LINK関連のオプション/メッセージ関連のオプション
プリプロセッサ関連のオプション
警告を要求/抑止するオプション

Copyright 2003 岸 哲夫

Copyright 1997-2024 CQ Publishing Co.,Ltd.