34732


フラグの管理用に0, 1が格納されているunsigned
char配列hogeがあるとして、この配列を元に「いづれかのフラグがたったらtrueを返す」様な関数をbit演算を駆使して作りたいと考えています。(bitを駆使したフラグ管理練習用なので「別にbit使わなくても...」は無しでお願いいたします)  
そこで、以下の様な関数を作成してみました。

[code]

    bool IsAnyFlag() const
    {
        unsigned int flags = 0;
        for (int i = 0; i < NUM; i++)
        {
            flags |= hoge[i] << i;
        }
        return flags != 0;
    }
    
[/code]

しかしこれでは、一応正常に動きはしますが「for文内で1だったら速攻true返せば早くね？」という話になってしまい、bitに直している意味が無いように感じてしまいます。

では、unsigned
char配列を一括でbit列に直せる方法があれば良いのではとも考えましたが、そのような方法は私が調べた限りでは無いようで頓挫しています。

あいまいな言葉で申し訳ないのですが、もっとスマートな方法はありませんでしょうか。  
よろしくお願いいたします。

余談ですがchar型が文字専用型ではないというのを最近知り「え！？ ちがうのぉ！？」と驚愕しております。


CC BY-SA 3.0
2017-05-15T11:57:16.337
34728
2017-08-05T17:19:24.823
2017-05-15T12:26:28.030
20642
20642
question
c++
0,1が格納されているunsigned char配列をbit列に直したい


[`std::find`](https://cpprefjp.github.io/reference/algorithm/find.html)を使えば特定の値を検索することができます。見つからなかった場合は`last`が返されるのでそれと比較すればいいでしょう。

[code]

    bool IsAnyFlag() const {
        return std::find(hoge, hoge + NUM, 1) != hoge + NUM;
    }
    
[/code]

* * *

### もっとスマートな方法はありませんでしょうか。

素直なコードを記述すればコンパイラーは効率的な処理を生成してくれます。例えば上記コードをVisual
C++でコンパイルするとC言語の`memchr`関数に展開されます。

もちろん`memchr`関数は自身の責任範囲内で効率的な検索を行います。int32_tさんが「大きな整数型でまとめて読むと早くなるケースがあります」と書かれていますが、例えば[glibcのmemchr](https://github.com/lattera/glibc/blob/master/string/memchr.c)なんかもアラインメントを考慮しながら`unsigned
long int`を使うことで複数まとめて読み込んでいます。Visual
C++も32bitに関してはアセンブラ言語で記述されており複数まとめて読み込んでいました。

結局、特殊なコードを記述するよりも、標準ライブラリを活用しシンプルな記述をすることが効率的かと思います。

* * *

### `std::find`と`boost::find`の違いについて

[Boost](https://ja.wikipedia.org/wiki/Boost)は

> Boostは考案された新機能を標準化させる前の試験運用の場であるとも言える。

という位置づけですので、STLとBoostとで全く同じ機能を持つ場合もあれば、STLに取り込まれる際に変更される場合もあり、またSTLに取り込まれた後にBoost側で更に新機能を追加される場合もあったりとまちまちです。`std::find`と`boost::find`とが似ているのもそのためです。


CC BY-SA 3.0
2017-05-15T14:15:49.530
34732
2017-05-17T05:04:35.357
2017-05-17T05:04:35.357
4236
4236
34728
answer


unsigned char[] から一括で bit 列にする方法は知りませんが、  
はじめから flags に各 bit を持たせておけば良いと思います。

[code]

    unsigned int flags = 0;
    void setFlag(int i) {
        flags |= 1 << i;
    }
    void clearFlag(int i) {
        flags &= ~(1 << i);
    }
    bool isAnyFlag(void) {
        return flags != 0;
    }
    
[/code]


CC BY-SA 3.0
2017-05-15T14:52:35.760
34733
2017-05-15T14:52:35.760
5288
34728
answer


ビットで表現されてないものをその場でビット表現に直してもスマートにはならないと思われます。ビット表現に直したものをあらかじめ作るかキャッシュすると意味があるかもしれません。

昔ながらの局所最適化で、大きな整数型でまとめて読むと早くなるケースがあります。が、スマートとは言い難いですね。

[code]

    alignas(int32_t) unsigned char hoge[NUM];
    
    bool IsAnyFlag() {
      assert(NUM % sizeof(int32_t) == 0);
      for (size_t i = 0; i < NUM; i += sizeof(int32_t)) {
        if (*reinterpret_cast<int32_t*>(&hoge[i]))
          return true;
      }
      return false;
    }
    
[/code]


CC BY-SA 3.0
2017-05-15T23:22:45.520
34738
2017-05-17T01:13:44.597
2017-05-17T01:13:44.597
3475
3475
34728
answer


「スマート」の定義がわかりませんが，まず前提として

> unsigned char配列を一括でbit列に直せる方法

については，質問文で書かれているビットシフトと論理和を使う方法が最もシンプルかと思います．

ただ，もしやりたいことが

> いづれかのフラグがたったらtrueを返す

であるなら，ビットシフトは必要ないように思います．

[code]

    bool any() const
    {
        std::uint8_t flag = 0;
        for(std::size_t i = 0; i < NUM; ++i) {
            flag |= hoge[i];
        }
        return flag != 0;
    }
    
[/code]

> for文内で1だったら速攻true返せば早くね？

については，最近のコンパイラは賢いのでうまいこと最適化してくれるかもしれませんが，ちょっと頭の悪い子だったりベクトル化が効く処理だったりすると，いちいち条件分岐する方が計算効率が悪くなり，「いっそ全部論理和をとってから最後に判定した方が早くね？」となる場合もあります．

もっとも，他の回答者さんが言及しているように「最初から整数値１つでフラグ情報を持つ」あるいは「最初からbitsetを使う」方が楽ですが…


CC BY-SA 3.0
2017-05-28T06:07:25.077
35084
2017-05-28T06:07:25.077
3091
34728
answer


たまたま
hoge配列の中にひとつでも1があるかどうかを判定するだけだからfor文の途中でリターンしていいだけでしょう。例えば、hoge[1]、hoge[3]、hoge[4]のどれかに1つ以上１が含まれていたら？とかいう問題なら、flags
& 0x16
が０でないかどうか判定すればflagsの存在意味は出るのではないでしょうか。この0x16のような「マスク」を引数に取る関数とか作ってみるとかしてはどうでしょうか。スマートと言っても練習目的ならこのぐらいでいいと思います。  
要素が0,1しか値をとらないのだったらhoge
をbool型配列にしてみるとか、シフトのかわりに（内容が、0x1、0x2、0x4、0x8、・・・の定数配列など利用して）マスクを使ってみるとか、いろいろやってみてから、C++の便利なクラスの使い方を学んでみるとか。std::vector
なんてものもあります。  
あと （unsigned）int型のサイズは処理系によって変わるかもしれませんから、std::uint32_t とか std::uint64_t
などの方を使う方がいいと思います。


CC BY-SA 3.0
2017-08-05T17:19:24.823
36967
2017-08-05T17:19:24.823
24517
34728
answer