パスワードを忘れた? アカウント作成
13892313 journal
日記

quaternionの日記: C言語で変数をスワップするマクロ 27

日記 by quaternion

H31春基本情報技術者試験問9(C言語)[PDF]で,変数をスワップするマクロが使われていた.本文中には

Swap(x, y) は x と y の内容を入れ替えるために用意したマクロである

とだけ書かれていて,その実装は与えられていない.

このようなSwapマクロはどのように書くのが正解だろうか?

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by manmos (29892) on 2019年05月10日 10時27分 (#3612109) 日記

    排他論理和の3回ですむのですが、浮動小数点やポインタが。

  • by kitune-san (48712) on 2019年04月21日 22時58分 (#3603295) 日記
    たしかトリッキーな方法でビット演算で移動する方法があったと思うのですが、それは置いといて、
    #define Swap(x, y) do { int z = y; y = x; x = z; } while (0)
    のようにdo - while (0)で囲むという方法もあります。
  • by Anonymous Coward on 2019年04月21日 23時38分 (#3603302)

    xとyが同じものだったりしたときに不安を覚える。
    なのでswap関数を用意するのが正解だと思う。
    これによってSwapマクロはswap関数を呼び出す極めてシンプルなものになる!

    • by quaternion (18655) on 2019年04月22日 7時32分 (#3603372) 日記

      C言語でswap関数を書けますか?

      親コメント
      • by Anonymous Coward

        void swap(int *x, int *y) { int z = *x; *x = *y; *y = z; }
        #define Swap(x, y) swap(&(x), &(y))
        これならint以外や右辺値を渡したときもちゃんとエラーになる

        • by quaternion (18655) on 2019年04月22日 14時15分 (#3603481) 日記
          問題文中のSwapマクロは int, int を受け取る場合と long, long を受け取る場合があるので,辛いと言えば辛いかも.
          親コメント
          • by Anonymous Coward

            まず一つ訂正。C言語ではポインターを異なる型へのポインターに変換してもエラーにはならなかった(規格で明示的に認められている)。アライメント要求に違反すると未定義動作になるし多くの場合アクセスした瞬間未定義動作になるしコンパイラーによっては警告を出すかもしれないけど。
            で、考えた結果こうなった。

            void swap(unsigned char *x, unsigned char *y, size_t s)
            {
                for (size_t i = 0; i < s; i++) {
                    unsigned char z = x[i];
                    x[i] = y[i];
                    y[i] = z;

    • by Anonymous Coward

      ここにぶら下げよう。
      前提についての質問ですけど、型の限定って出来ましたっけ?
      単に内容を入れ替えるマクロだと、違う型が指定されたり
      想定している型(int)以外が指定されたり。
      親コメの言う通りswap関数用意した方が良さそう。

  • by Anonymous Coward on 2019年04月22日 1時28分 (#3603335)

    ・そのようなマクロは書くべきではないし、書こうと考えてもいけない
    ・問題の理解のために必要であれば、必要最低限の実装でよい

    • by Anonymous Coward

      俺の言うことを守らないと、仕事や教育そっちのけでパズルに走る無能のカスになるよ

    • by Anonymous Coward

      その方向性を突き詰めたら
      ・C言語でプログラムを書くべきではないし、書こうと考えてもいけない
      ・基本情報の言語の選択はCASLマジオススメ
      ってなると思う

  • by Anonymous Coward on 2019年04月22日 7時11分 (#3603366)

    //xとyの値を入れ替える。xとyの型は同じでなければならない
    #define Swap(x,y){
        unsigned int __i = 0;
        unsigned char __t;
        void *p1 = (void*)&x;
        void *p2 = (void*)&y;
        while(i<size_t(x)){
            __t = ((unsigned char*)&x)[__i];
            ((unsigned char*)&x)[__i] = ((unsigned char*)&y)[__i];
            ((unsigned char*)&y)[__i] = __t;
            __i++;
        }
    }

    • by Anonymous Coward

      リンク先今読んだ(^^;
      do{}while(0);で囲めば{}省略ifの中で使われても大丈夫じゃないかな...

    • by Anonymous Coward

      __iや__tのようなアンダースコア2つを含む名前を使ってはいけない。標準ライブラリヘッダーでは使っているかもしれないが、それはまさに標準ライブラリヘッダーなどが使うために予約されているからであって、ユーザープログラムで使い出したら台無しになる。

      • by Anonymous Coward

        失礼、どこであれ含んではいけないのはC++だった。C言語ではアンダースコア2つが予約されているのは先頭に来るときだけだった(つまり結局ダメ)。

    • by Anonymous Coward

      > while(i<size_t(x)){

      もしかして: sizeof(x)

    • by Anonymous Coward

      Swap(*p++, y)とかやったらヤバくない?

  • 多分下記が最低ライン。
    #define Swap(x, y) do{(x)^=(y); (y)^=(x); (x)^=(y);}while(0)

    そもそもコード規約でdefineマクロを縛ってる所も有りますね。
    複文になった時点で、関数化がデフォルトで基本マクロは不可。
    どうしても書く場合は落とし穴に詳しい人のコードレビューを通らないとダメ。

    ちなみに、引数を括弧で括ってないのは全てダメ。
    Swap(x+1,y);みたいなアホな事されたときにエラーにならないかもしれない。
    どっちにしろ、Swap(++x,y)みたいなのには無力なので関数にしましょう。

    結論:単なる文字置換なので複雑な事(複文が必要な事)をしたらアカン。

typodupeerror

人生unstable -- あるハッカー

読み込み中...