ESP32入門 通信機能が標準搭載されたマイコン・ボード (9)の補足説明

snprintf()の使い方

 ESP32マイコン・ボードとWi-Fi経由でWebブラウザで通信を行うプログラムを「ESP32入門 通信機能が標準搭載されたマイコン・ボード」の記事で紹介しました。その中で9回目の、測定した温度をWebに表示①の記事で使用したsnprintf()関数の使い方について読者から質問がありました。

  ESP32入門 通信機能が標準搭載されたマイコン・ボード (9)
  測定した温度をWebに表示①
  https://www.denshi.club/cookbook/arduino/esp32/esp32-9-web.html

 この記事で利用したsnprintf()について具体例をもとに説明します。まず規格を調べます。JISのC言語の規格のsnprintf()関数は次のように規定されています。

JIS規格のsnprintf

 JISのC言語の仕様書 JIS X 3010 :2003にsnprintf関数が次のように定義されています。


7.19.6.4 snprinf 関数

◆形式
#include <stdio.h>
  int snprintf(char * restrict s, size_t n,
  const char * restrict format, ...);

◆機能
 snprintf 関数は,生成された出力をストリームではなく実引数 s で指定する配列に書き込むことを除いて,fprintf 関数と等価とする。n が 0 の場合,snprintf 関数は何も書き込まず,s は空ポインタでもよい。その他の場合,n-1番目より後の出力文字は配列に書き込まずに捨て,配列に実際に書き込んだ文字の列の後にナル文字を書き込む。領域の重なり合うオブジェクト間でコピーが行われるとき,その動作は未定義とする。

◆返却値
snprintf 関数は,n が十分に大きい場合に配列に書き込んだはずの文字数を返す。ただし,終端ナル文字は数えない。表現形式エラーが発生した場合,負の値を返す。すなわち,返却値が非負かつ n未満の場合,そしてその場合に限り,ナル文字で終了している出力が完全に書き込まれている。

筆者の解釈

 規格書の記述は少々わかりにくいので、実際にこの命令をArduinoのプログラムの中で利用して記述するときに、筆者がどのような思いで記述しているかまとめてみます。

◆書式
 書式にある#include <stdio.h>の記述は、Arduino IDEのコンパイラが対応していますから、Arduino IDEで利用するときは記述を省略できます。

 snprintf(文字列配列、最大文字数、フォーマットの文字列、変換指定子対象の変数);

文字列配列 : 変数を変換指定子の指定に従い変換し、文字列で設定された見出しを含めて新しい配列を構成し、第一の引数で指定した文字列配列に設定する。

最大文字数 : 配列に設定する文字数の最大値を設定する。この値は配列の大きさを超えない値とする。

フォーマットの文字列 : 説明や見出しなどと変換指定子が組み合わされたフォーマットを指定するための文字列。変換指定子は次に続く変換対象の変数と対応している。

変換指定子対象の変数 :変換指定子の変換対象となる変数で、変数の数は変換指定子の数に対応している。

 フォーマットの文字列の中で設定する書式は「JIS X 3010 :2003」の7.19.6.1 fprintf関数(p.198)の説明を参考に、書式の設定方法を以下にまとめました。

書式の設定方法 : 変換の書式は次のようになります。

% フラグ フィールド幅 精度 長さ修飾子 変換指定子

 変換指定の最初は  の文字から始まる。続く各項目は次のような役割を担う。

フラグ (省略可能、複数設定可) 

  -  : 変換結果を左詰めに表示する。この指定がないと右詰めになる
  +  : 符号付きの変換結果は常に+または-の符号で始まる。この符号がないとマイナスのときのみ符号が付く。
 空白  : 符号付きの変換結果の符号が付かない場合、または変換結果の文字数が0の場合先頭に空白1文字追加しマイナスの値と位置を合わせる。
  #   : 数値データが変換指定子に従って変換された結果に、それぞれ対応した処理を付加する。
 変換指定子が Oの場合  変換された8進数に oを追加
 変換指定子が x、Xの場合 結果に 0xまたは0Xを追加
 変換指定子が e、E、f の場合 結果に 小数点を付ける
 変換指定子が g、G の場合  上記に加え少数以下の0を省略しない
  0  :  数値の場合先行0埋めを行う

フィールド幅(省略可)

 数値  : 変換結果の最小フィールドを指定します。文字数が指定より少ない場合、0または空白で埋められる。また、文字数が指定より大きい場合はこの指定は無視され、変換された結果を表示する。

精度(省略可)

 .n : フィールド幅の次に小数点と精度を示す数値を設定する。変換指定子ごと
      に、この精度の機能は次のようになる。
      d、i、o、u、x、X の場合 出力文字数の最小値を示す。
      a、A、e、E、f の場合 小数以下の文字数を示す
      g、G の場合  有効数字の最大桁数を示す
 .0  :  小数以下の数値を小数点も含めて表示しない。

長さ修飾子(省略可)

      実引数の大きさを指定する修飾子。この修飾子の意味は次のようになる。
 h   : 変換指定子がd、i、o、u、x、Xの場合 実引数がshort int型かunsigned short
int型であることを示す。
 l   : 変換指定子がd、i、o、u、x、Xの場合 実引数がlong int型かunsigned long int型であることを示す。
 ll   : 変換指定子がd、i、o、u、x、Xの場合 実引数がlong long int型かunsigned long long int型であることを示す。

変換指定子

   d、i  : 10進数で出力する
  o   : 8進数で出力する
  u   : 符号なし10進数で出力する
  x、X  : 16進数で出力する
  f、F : 浮動小数点数のダブル型の実引数を、小数点表示の10進数で出力する。
        小数以下の値は精度に指定された桁数とする。精度の指定がないときは小数以下6桁の表示となる。  
  e、E  : 浮動小数点数のダブル型の実引数を指数表示で出力する。小数以下の表示
桁数は精度で示された桁数で、精度が省略されたときは6桁となる。
        小数点以上の表示桁は1桁となる。
  g、G : 浮動小数点数のダブル型の実引数を有効桁数で指定された精度に従い、gの場合f形式、e形式の表示を行う。Gの場合F形式、E形式の表示を行う。
  c   :  文字として出力する
  s   :  文字列として出力する。
  P   :  ポインタを出力する
  n  :  文字列の先頭からこの%nの文字に到達するまでの文字数を、引数で指定
されるint型の変数にセットする。
  %   :  % を表示するときこの変換指定子を利用する

restrict ポインタに対する修飾子。このrestrict修飾子で指定されたポインタは同一のオブジェクトに対して複数のポインタを介してアクセスすることがないように記述されていて、プログラムの最適化が行われても不都合がないことをコンパイラに示すためのものです。上記の条件を守る責任はプログラマにあります。またこの修飾子はコンパイラに対する指定でプログラムの動作に関しては何ら影響を与えません。プログラムの動作を考えるときはこの修飾子はあってもなくても同じです。

 以上の規格のまとめに従い、次の項目でWebブラウザに表示するためのデータ作成を行っているsnprintf()関数について説明します。

  ESP32入門 通信機能が標準搭載されたマイコン・ボード (9)
  測定した温度をWebに表示①
  https://www.denshi.club/cookbook/arduino/esp32/esp32-9-web.html

実際の関数の記述

 この関数の3番目の引数の”<html> から </html>“までが、書式を決める文字列です。

snprintf(temp, 400,
"<html>\ // ブラウザで表示するためのHTML文書の開始を示す
<head>\ // 次のhttp-equiv='refresh'で自動更新が指定されている
<meta http-equiv='refresh' content='3'/>\ // 間隔は3秒に設定されている
<title>Denshi Club ESP32 test</title>\ // 文書のタイトルで画面には表示されない
<style>\ // バックグラウンドのカラー・コード、フォント、文字の色を指定
body{background-color:#40e0d0;font-family:Arial,Helvetica,Sans-Serif;Color:#000000;}\
</style>\
</head>\
<body>\
<h1>Temperature from ESP32</h1>\
<p>Uptime: %02d:%02d:%02d</p>\ // 経過時間の書式
<p>Temperature: %8.2f</p>\    // 温度の書式
</body>\
</html>",
hr, min % 60, sec % 60,  //経過時間の実引数
tvalue          // 測定温度の実引数
);

測定データの表示の仕様を決める

 次のUptimeは見出しでは、その後の%02dが時間の表示をフラグが0でゼロ・サプレス、フィールド長を2桁で、変換指定子がdで十進数表示を指定しています。時分秒の間に分離のための:が挿入されています。書式は同じ指定となっています。
 次の行のTemperature:は温度測定の見出しでは、フィールド長が8桁、精度が2桁で実数表示のfの変換指定子で書式が設定されています。

<p>Uptime: %02d:%02d:%02d</p>\
<p>Temperature: %8.2f</p>

 対応する実引数が、書式の文字列の引数の次の引数として設定しています。

実行結果

 実行結果について、経過時間は2桁の時:分:秒で表示され、温度は小数以下2桁の実数値として表示されています。
 経過時間の表示の値が1桁の場合ゼロ・サプレスが行われていなく空白のようです。テスト時には気づかず確認が漏れていました。現在システムをばらしているので、再度組み立ててArduinoの仕様なのか確認します。

(2020/4/18 V1.0)

<神崎康宏>

前へ

初めてのBLE (19) CircuitPythonでペリフェラル③ BME280

次へ

Nano 33 BLE Senseでマルチセンサ・ペリフェラルを作る (1) BLEとは