yohhoyの日記

技術的メモをしていきたい日記

scanf文字列取得と動的メモリ確保

C標準ライブラリscanf関数の書式指定%sにおいて、取得先の文字列バッファを動的確保する機能拡張。

// POSIX準拠システム
char *s = NULL;
scanf("%ms", &s);  // sはmallocで確保される
...
free(s);

まとめ:

  • 標準C(ISO C):該当機能は存在しない。メモリ領域を事前確保し、書式指定%sには領域サイズを指定すること。*1
  • POSIX準拠システム:動的メモリ確保を行うオプション文字mが存在する。
  • LSB準拠システム:動的メモリ確保を行うオプション文字aが存在するが、これはC99標準の16進浮動小数%a指定と衝突する。*2

POSIX

オプション文字mはThe Open Group Base Specifications Issue 6/IEEE Std 1003.1-2008で追加*3されている。POSIX規格(IEEE Std 1003.1-2013)より引用。

The %c, %s, and %[ conversion specifiers shall accept an optional assignment-allocation character 'm', which shall cause a memory buffer to be allocated to hold the string converted including a terminating null character. In such a case, the argument corresponding to the conversion specifier should be a reference to a pointer variable that will receive a pointer to the allocated buffer. The system shall allocate a buffer as if malloc() had been called. The application shall be responsible for freeing the memory after usage. If there is insufficient memory to allocate a buffer, the function shall set errno to [ENOMEM] and a conversion error shall result. If the function returns EOF, any memory successfully allocated for parameters using assignment-allocation character 'm' by this call shall be freed before the function returns.

The Open Group Base Specifications Issue 7, fscanf, scanf, sscanf - convert formatted input

Linux Standard Base(LSB)

LSB 5.0 Core specificationより引用。

Description
The scanf() family of functions shall behave as described in POSIX 1003.1-2008 (ISO/IEC 9945-2009), except as noted below.
Differences
The %s, %S and %[ conversion specifiers shall accept an option length modifier a, which shall cause a memory buffer to be allocated to hold the string converted. In such a case, the argument corresponding to the conversion specifier should be a reference to a pointer value that will receive a pointer to the allocated buffer. If there is insufficient memory to allocate a buffer, the function may set errno to ENOMEM and a conversion error results.

Note: This directly conflicts with the ISO C (1999) usage of %a as a conversion specifier for hexadecimal float values. While this conversion specifier should be supported, a format specifier such as "%aseconds" will have a different meaning on an LSB conforming system.

Linux Standard Base Core Specification, 14.5. Interface Definitions for libc, scanf

Linux/glibcライブラリのマニュアルには本件に関するノートが存在し、mオプション(POSIX準拠)の利用が推奨されている。

'a' 代入割り当て(assignment-allocation)修飾子
元々、GNU Cライブラリ(glibc)では、a 文字による文字列入力に対する動的割り当て変換指定子(dynamic allocation conversion specifier)を (非標準の拡張として) サポートしている。この機能は少なくとも glibc 2.0 の時点ではすでに存在している。(略)

a 修飾子は gcc -std=c99 や gcc -D_ISOC99_SOURCE でコンパイルしたプログラムでは (_GNU_SOURCE も同時に指定していない場合) 利用できない点に注意。この場合、a は (上述の通り) 浮動小数点数を示す変換指定子と解釈される。

m 修飾子への対応はバージョン 2.7 以降の glibc で追加されている。新しいプログラムでは a の代わりに m を使用すべきである。

https://linuxjm.osdn.jp/html/LDP_man-pages/man3/scanf.3.html

関連URL

*1:バッファオーバーランによるセキュリティホール回避措置。JPCERT STR35-C参照。

*2:scanf関数ファミリへの書式指定子では a, e, f, g に機能的な差異はない。(C99 7.19.6.2/p12)

*3:http://www.opengroup.org/austin/aardvark/latest/xshbug2.txt "Enhancement Request Number 132"