fgetcのバッファサイズ

前回までで、fgetcは中身はポインタ操作のマクロを呼び出していることが分かりました(debianの場合)。

#define _IO_getc_unlocked(_fp) \
       (_IO_BE ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end, 0) \
	? __uflow (_fp) : *(unsigned char *) (_fp)->_IO_read_ptr++)

さて、バッファサイズはどれだけなんでしょうか。gdbで確認してみます。
使うソースです。

takk@deb9:~/tmp$ cat -n b.c
     1	#include <stdio.h>
     2	
     3	int main()
     4	{
     5		int c;
     6		FILE *fp;
     7		fp = fopen("test.dat","r");
     8		while((c=fgetc(fp)) != -1){
     9			fputc(c,stdout);
    10		}
    11		fclose(fp);
    12	
    13		return 0;
    14	}
takk@deb9:~/tmp$ 

gdb用にビルドしておきます。

takk@deb9:~/tmp$ gcc -g -o b.out b.c
takk@deb9:~/tmp$ 
takk@deb9:~/tmp$ gdb b.out

~省略~

(gdb) r
Starting program: /home/takk/tmp/b.out 

Breakpoint 1, main () at b.c:8
8		fp = fopen("test.dat","r");
(gdb) p/x fp
$1 = 0x0
(gdb) p/x *fp
Cannot access memory at address 0x0
(gdb) 

fopen実行前では当然、fp変数な初期化前です。

(gdb) n
9		while((c=fgetc(fp)) != -1){
(gdb) p/x fp
$2 = 0x555555756010
(gdb) p/x *fp
$3 = {_flags = 0xfbad2488, _IO_read_ptr = 0x0, _IO_read_end = 0x0, 
  _IO_read_base = 0x0, _IO_write_base = 0x0, _IO_write_ptr = 0x0, 
  _IO_write_end = 0x0, _IO_buf_base = 0x0, _IO_buf_end = 0x0, 
  _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0, 
  _markers = 0x0, _chain = 0x7ffff7dd4520, _fileno = 0x3, _flags2 = 0x0, 
  _old_offset = 0x0, _cur_column = 0x0, _vtable_offset = 0x0, _shortbuf = {
    0x0}, _lock = 0x5555557560f0, _offset = 0xffffffffffffffff, __pad1 = 0x0, 
  __pad2 = 0x555555756100, __pad3 = 0x0, __pad4 = 0x0, __pad5 = 0x0, 
  _mode = 0x0, _unused2 = {0x0 <repeats 20 times>}}
(gdb) 

fopen実行後は、fpは存在しますが、マクロで使われていた_IO_read_ptrと_IO_read_endが0になってます。意外です。fopenで設定されるものだと思ってました。

fputcの実行後を見てみます。

(gdb) n
10			fputc(c,stdout);
(gdb) p/x fp
$4 = 0x555555756010
(gdb) p/x *fp
$5 = {_flags = 0xfbad2488, _IO_read_ptr = 0x555555756241, 
  _IO_read_end = 0x555555757240, _IO_read_base = 0x555555756240, 
  _IO_write_base = 0x555555756240, _IO_write_ptr = 0x555555756240, 
  _IO_write_end = 0x555555756240, _IO_buf_base = 0x555555756240, 
  _IO_buf_end = 0x555555757240, _IO_save_base = 0x0, _IO_backup_base = 0x0, 
  _IO_save_end = 0x0, _markers = 0x0, _chain = 0x7ffff7dd4520, _fileno = 0x3, 
  _flags2 = 0x0, _old_offset = 0x0, _cur_column = 0x0, _vtable_offset = 0x0, 
  _shortbuf = {0x0}, _lock = 0x5555557560f0, _offset = 0xffffffffffffffff, 
  __pad1 = 0x0, __pad2 = 0x555555756100, __pad3 = 0x0, __pad4 = 0x0, 
  __pad5 = 0x0, _mode = 0xffffffff, _unused2 = {0x0 <repeats 20 times>}}
(gdb) 

各メンバにアドレスが設定されています。
おそらく_IO_read_baseがリードバッファの先頭アドレスですが、
そのアドレスから+1の値が、_IO_read_ptrの値となっています。
先頭バッファの値を、読み終わったことが分かります。

さて、バッファサイズを確認します。
endからbaseを引けばいいので、

(gdb) p fp->_IO_read_end - fp->_IO_read_base
$6 = 4096
(gdb) 

4096Byteでした。

次は、setvbufを使います。
setvbufを使うと、バッファサイズが変更できます。

takk@deb9:~/tmp$ cat -n c.c
     1	#include <stdio.h>
     2	
     3	char buf[1024];
     4	int main()
     5	{
     6		int c;
     7		FILE *fp;
     8		fp = fopen("test.dat","r");
     9		setvbuf(fp,buf,_IOFBF,1024);
    10		while((c=fgetc(fp)) != -1){
    11			fputc(c,stdout);
    12		}
    13		fclose(fp);
    14	
    15		return 0;
    16	}
takk@deb9:~/tmp$ 

1024Byteにしてみました。
fopenの後に、setvbufを実行することで、このプログラムでは1024Byteのバッファにすり替えています。

さて、gdb用にビルド。

takk@deb9:~/tmp$ gcc -g -o c.out c.c
takk@deb9:~/tmp$ 

gdb実行します。

takk@deb9:~/tmp$ gdb c.out

~省略~

(gdb) b main
Breakpoint 1 at 0x818: file c.c, line 8.
(gdb) r
Starting program: /home/takk/tmp/c.out 

Breakpoint 1, main () at c.c:8
8		fp = fopen("test.dat","r");
(gdb) n
9		setvbuf(fp,buf,_IOFBF,1024);
(gdb) 
10		while((c=fgetc(fp)) != -1){
(gdb) 
11			fputc(c,stdout);
(gdb) p/x fp
$1 = 0x555555756010
(gdb) p/x *fp
$2 = {_flags = 0xfbad2489, _IO_read_ptr = 0x555555755081, 
  _IO_read_end = 0x555555755480, _IO_read_base = 0x555555755080, 
  _IO_write_base = 0x555555755080, _IO_write_ptr = 0x555555755080, 
  _IO_write_end = 0x555555755080, _IO_buf_base = 0x555555755080, 
  _IO_buf_end = 0x555555755480, _IO_save_base = 0x0, _IO_backup_base = 0x0, 
  _IO_save_end = 0x0, _markers = 0x0, _chain = 0x7ffff7dd4520, _fileno = 0x3, 
  _flags2 = 0x0, _old_offset = 0x0, _cur_column = 0x0, _vtable_offset = 0x0, 
  _shortbuf = {0x0}, _lock = 0x5555557560f0, _offset = 0xffffffffffffffff, 
  __pad1 = 0x0, __pad2 = 0x555555756100, __pad3 = 0x0, __pad4 = 0x0, 
  __pad5 = 0x0, _mode = 0xffffffff, _unused2 = {0x0 <repeats 20 times>}}
(gdb) p fp->_IO_read_end - fp->_IO_read_base
$3 = 1024
(gdb) 

いきなりend-baseを算出してみました。
1024Byteになっていますね。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA