scanf() について

RL78/G23 FreeRTOS 10.5.1  で以下のようなタスクを作りました。 

char c;
int ret;

while(1)
{
    ret = scanf("%c", &c);
    ret = printf("%c", c);
}/* while */

int getchar(void)
{
    size_t result;
    uint8_t chr;

    while (1)
    {
        result = xStreamBufferReceive(stream_bff_handle_UART0, &chr, sizeof chr, portMAX_DELAY);
        if (result > 0)
        {
            break;
        }
        else
        {
        }
    }//while

    return chr;
}

シリアル受信割り込み内部の xStreamBufferSendFromISR() で受信データーを getchar() -> scanf() と渡すのですが
ABCDEFGH が ACEG となりました。
受信データーが getchar() にくることは確認したので getchar() -> scanf() に絞り
%c を %d に換え、getchar() から 0 から +1 する(インクリメント)データーを送ると scanf() 側は A5A5 固定となります。
getchar() から戻るところをデバッガーで見るとインクリメントしたデーターを戻しているのです
標準関数に問題はないのでしょうか?

  • 大変お世話になっております。
    SAM です。

    分かりにくい文面ですみません。
    int getchar(void) は説明のために追加したものです。
    while ループのところがタスクです。

    下書きのようなものが流れてしまいました。すみません。
    標準関数は、ソースコードが無いので
    もし分かる方がいらっしゃればと思い質問させて頂きました。
    よろしくお願いします。

  • getcharの戻り値はEOFも取ります。
    OSレスのscanfは実装したことがありますが、文字データを入力装置から取得できない時にEOFを返す作りにする必要があったはずです。
    getcharの実装でwhile文がありますがこれがおかしいのではないかと思います。

  • Yamamoto さん
    返信ありがとうございます。

    A5A5 と返ってくるときの getchar() を以下に示します。

    int getchar(void)
    {
    static int i = 0xFFFF;

    i++;
    vTaskDelay(pdMS_TO_TICKS(1000));

    return i;
    }


    int i, ret;
    ret = scanf("%d", &i);
    ret = printf("%*X", sizeof(int) * 2, i);

    scanf() で受けた i には 0xA5A5 と入っています。
    getchar で返したものが入ってくれないのでしょうか。

    while文で囲った部分については修正して確認してみます。

  • やっていることを私が正しく理解できているのかというのがありますが、scanfの%dで取得できるのは文字列表現の整数値を整数に変換して指定ポイント先に格納するだけです。実験で作成されたgetcharの実装ではそもそもASCIIコードの'0'(30H)から'9'(39H)の文字コードを含んでいないのですがそれは意図してそうやっているのでしょうか?

    整数文字表現に使う文字コードの範囲外を与えてどう動くのか?は私は良くわかりません。下のようなテストコードでどう動きますか?これは疑似乱数で選んだ0から9の数字のコードを4つ返したらEOFするものです。もしかするとscanfには文字表現数値の終わりに改行コードを返す作りがgetcharに必要かもしれません。処理系によっては改行コードが2バイトかもしれません。

    int getchar(void)
    {
    const static char table[]={'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    static int n = 0;
    if (n < 4) {
    n++;
    return (int)table[rand()%10];
    } else {
    n = 0;
    return EOF;
    }
    }
  • Yamamoto さん
    ご返信、ご指摘ありがとうございます。

    私は間違った方向に向かっていました。
    ご指摘の while ループは既に取り除いていますが、
    ABCDE が ACE になるような1つ飛び現象は変わりません。

    const int data[] = {'0', '0', '4', '3', '\0'};

    上記を順番に送って、%d で 43 、 %X で 0x43 として変数に格納されるので
    scanf() の動作に間違いは無いのですが、出力をサボっているように見えます。

    scanf(), printf() について H8 RX はライブラリ内部の low level の関数を変更していますが
    RL78 は標準関数 putchar getchar を変更することに違和感があります。
    scanf, printf の入出力先を変えるのに putchar getchar を変更するとあったのですが
    実は専用の関数があるのでしょうか?

  • ペリフェラルとしてのUARTとインターフェースする部分の関数の実装はコンパイラによって扱いが違った記憶があります。私はマイコン変更にも対応できるようにすることを考えてコンパイラ依存を排除したいというのがあるのでUARTのFIFOライブラリを自前でマイコン依存として用意し、scanfやprintfを直接使ってUARTにアクセスせずにsscanfとspintfを使って文字列を経由して自前のFIFOライブラリに突っ込むようにしています。なのでそれぞれのコンパイラの想定するやり方は把握しておりません。

    過去の投稿で今回の件と関係しそうなのがありましたよ。
    https://community-ja.renesas.com/cafe_rene/forums-groups/mcu-mpu/rl78/f/forum18/4024/cc-rl-uart-rl78-putchar-getchar-printf-scanf

    なおnewlibを使っている場合はprintfを実装した時点でstdoutに対してのファイルIOのために下が足りないって出るかなと思います(gccを使ったARM系ではそん感じだった記憶が)。もしくは中身のない空の宣言をオーバーライドする(シンボルが内部でweakで用意されているので自前で用意せずともビルドは通る)。

    • close
    • fstat
    • isatty
    • lseek
    • read
    • write
  • Yamamoto さん
    ご返信ありがとうございます。

    FreeRTOS+CLI を導入し、その中で getchar() を使って受信できるようにしました。
    標準関数を使いたかったのは、RX, RL78 共通にしたかったからです。
    RX では charget() を書き換えて scanf("%c", &c); を平気で使っていました。
    RL78 では、このようなことは出来ないのは常識だったようで
    Renesas さんまで巻き込んで大変お恥ずかしい限りです。
    ありがとうございました。