C言語の引数

RL78
CS+ forCC
でソフトを作っています。
例えば、関数 void xxfunc(uint32_t, uint32_t) があったとします。

メインで、
  uint16_t  aa;
  uint16_t  bb;
 
  aa = 1000;
  bb = 6000;
 xxfunc(aa, bb);
でコンパイルします。

引数の型が合わないのでワーニングが出ると思いましたが出ませんでいた。
暗黙の型変換だと思います。
このような場合でもワーニングを出すことはできますか?

Parents
  • > 例えば、関数 void xxfunc(uint32_t, uint32_t) があったとします。
    >
    > メインで、
    > uint16_t aa;
    > uint16_t bb;
    >
    > aa = 1000;
    > bb = 6000;
    > xxfunc(aa, bb);
    > でコンパイルします。
    >
    > 引数の型が合わないのでワーニングが出ると思いましたが出ませんでいた。
    > 暗黙の型変換だと思います。

    警告が出る出ないはさておいて、この場合の暗黙の型変換に何か問題がありますか?
    暗黙の型変換すべてをなくしたいということであれば上記のコードは aa や bb の初期化も

    aa = (uint16_t)1000U;
    bb = (uint16_t)6000U;

    等とするべきと思いますが現実的とも思いません。
  • 要は、関数の引数がuit32_tなのでuint16_tのaaを代入する場合、
    「型があってませんよ」という警告を出してほしいという意味です。
    例では、そのまま代入しても害はないことは分かっています。
  • 無意味なことを要望されてるということですか
  • > 要は、関数の引数がuit32_tなのでuint16_tのaaを代入する場合、
    > 「型があってませんよ」という警告を出してほしいという意味です。

    C とは異なり引数型の違いをエラーとしてくれる言語は存在するのでそちらの選択を検討されるのもひとつの手ではないかと思います。

    Swift Rust Ada

  • 例えば gcc では下記のような記述をすることで引数のサイズと符号の有無のチェック程度は可能です。

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    #include <assert.h>
    
    #define xxfunc(x, y) \
    ({ \
        assert(sizeof(x) == sizeof(uint32_t)); \
        assert((typeof(x))-1 == (uint32_t)-1); \
        assert(sizeof(y) == sizeof(uint32_t)); \
        assert((typeof(y))-1 == (uint32_t)-1); \
        _xxfunc(x, y); \
    })
    uint32_t _xxfunc(uint32_t x, uint32_t y)
    {
        return x + y;
    }
    
    int main(void)
    {
        uint16_t aa = 1000;
        uint16_t bb = 6000;
        uint32_t cc = xxfunc(aa, bb);
        printf("%"PRIu16 " + %"PRIu16 " = %"PRIu32 "\n", aa, bb, cc);
    }
    

    Wandboxで実行

    gcc の拡張文法を使用していますが似たようなことは CC-RL 等でも可能でしょう。

    記述が煩雑になることとそもそもの話大きい型への暗黙の変換に問題があると思わないのでお勧めしません。

Reply
  • 例えば gcc では下記のような記述をすることで引数のサイズと符号の有無のチェック程度は可能です。

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    #include <assert.h>
    
    #define xxfunc(x, y) \
    ({ \
        assert(sizeof(x) == sizeof(uint32_t)); \
        assert((typeof(x))-1 == (uint32_t)-1); \
        assert(sizeof(y) == sizeof(uint32_t)); \
        assert((typeof(y))-1 == (uint32_t)-1); \
        _xxfunc(x, y); \
    })
    uint32_t _xxfunc(uint32_t x, uint32_t y)
    {
        return x + y;
    }
    
    int main(void)
    {
        uint16_t aa = 1000;
        uint16_t bb = 6000;
        uint32_t cc = xxfunc(aa, bb);
        printf("%"PRIu16 " + %"PRIu16 " = %"PRIu32 "\n", aa, bb, cc);
    }
    

    Wandboxで実行

    gcc の拡張文法を使用していますが似たようなことは CC-RL 等でも可能でしょう。

    記述が煩雑になることとそもそもの話大きい型への暗黙の変換に問題があると思わないのでお勧めしません。

Children
  • 構造体に入れてしまえば引数型の違いは全てエラーにできますね。

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    typedef struct {
        uint16_t content;
    } uint16_s;
    
    typedef struct {
        int16_t content;
    } int16_s;
    
    typedef struct {
        uint32_t content;
    } uint32_s;
    
    typedef struct {
        int32_t content;
    } int32_s;
    
    uint32_s xxfunc(uint32_s x, uint32_s y)
    {
        uint32_s z = {x.content + y.content};
        return z;
    }
    
    int main(void)
    {
        uint16_s aa = {1000};
        int32_s  bb = {6000};
        uint32_s cc = xxfunc(aa, bb);
        printf("%"PRIu16 " + %"PRId32 " = %"PRIu32 "\n", aa.content, bb.content, cc.content);
    }
    

    Wandboxで実行

    勿論お勧めしません

  • 結局のところ関数への引数をすべてポインタ渡しするのが最も現実的なのではないかなと思います。

    #include <stdio.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    void xxfunc(uint32_t* z, const uint32_t* x, const uint32_t* y)
    {
        *z = *x + *y;
    }
    
    int main(void)
    {
        uint16_t aa = 1000;
        int32_t  bb = 6000;
        uint32_t cc;
        xxfunc(&cc, &aa, &bb);
    }
    

    CC-RL で警告が出ることを確認しました。

    main.c(15):W0520167:"uint16_t __near *" 型の引数は型 "const uint32_t *__near" の引数と整合しません。
    main.c(15):W0520167:"int32_t __near *" 型の引数は型 "const uint32_t *__near" の引数と整合しません。
    

    gcc でも同様です。

    Wandboxで実行

    無論、こういった書き方はお勧めいたしません。