質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

5322閲覧

C++ 32bit分の数値を前半16bitと後半の16bitずつに分けて取り出す方法

退会済みユーザー

退会済みユーザー

総合スコア0

Visual C++

Microsoft Visual C++はWindowsのCとC++の統合開発環境(IDE)であり、コンパイラやデバッガを含んでいます。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/04/08 07:37

VisualStudio2015 VisualC++ Windows10 63bit

C++で32bit分取得した値から、前半の16bitと後半の16bitをそれぞれ別の変数に入れたいのですが、どのようにすればよいのでしょうか。

思いついた方法として、
「1桁ずつシフトして配列に格納し、それを順番に取り出す。」
方法を思いついたのですが、あまりにも遠回り感が否めないので、もっと効率よくできないかと思い質問いたします。

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Nyaf

2019/04/08 07:46

「C++で32bit分取得した値」 というのは int の変数でしょうか?
退会済みユーザー

退会済みユーザー

2019/04/08 08:08

修正依頼ありがとうございます。 情報を正しく記載できずに申し訳ありません。 unsigned long 型です。
guest

回答4

0

ベストアンサー

上位16ビット ((data>>16)&0xffff)
下位16ビット (data&0xffff)

前16ビット ((uint16_t*)&data)[0]
後16ビット ((uint16_t*)&data)[1]

ましかし、エンディアンによって結果が変わるようなコードはダメダメなので書かないようにしましょう

投稿2019/04/08 07:53

編集2019/04/08 07:58
y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/04/08 08:10

>>y_waiwai様 回答ありがとうございます。 今回はエンディアンは必ずビッグで来るためご指摘いただいた内容は大丈夫だと思っておりますが、その場合でも何かしら考慮は必要でしょうか。
y_waiwai

2019/04/08 08:17

まあ、その場限りのコードなら別にいいですが、 「必ず」という言葉は必ず裏切られる、と思っておいたほうがいいかと。
pepperleaf

2019/04/10 14:47 編集

> エンディアンは必ずビッグで ## データを読み込んだ時点で、ビッグ/リトルは関係ありません。 <-- 取り消し、うっかりしてました。 もっともこの方法、Cのコードかと。(まあ、動くけど)
guest

0

こんにちは。

こんな感じでいけますよ。

C++

1#include <iostream> 2 3uint16_t high(uint32_t data) { return static_cast<uint16_t>(data >> 16); } 4uint16_t low(uint32_t data) { return static_cast<uint16_t>(data); } 5 6int main() 7{ 8 std::cout << std::hex << high(0x012345678) << "\n"; 9 std::cout << std::hex << low(0x012345678) << "\n"; 10}

static_castは本来不要ですが、msvcだと警告が出てうざいので。

投稿2019/04/08 07:45

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/04/08 08:12

>>Chironian様 早速のご回答ありがとうございます。 テストコードまで記載していただきとても助かります。 一度試してみようと思います。
guest

0

HIWORD,LOWORDマクロが使えます。
参考:MAKEWPARAM, HIWORD, LOWORD マクロとは?

投稿2019/04/08 07:45

can110

総合スコア38266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

別解としてはstd::memcpyを使うことでしょうか。

cpp

1std::uint32_t u32 = 4; 2std::uint16_t u16[2]; 3std::memcpy(u16, &u32, 4);

32bitの配列を16bitの配列に直すような場合はshift演算より楽かも。

なおこの手の着想でよくポインタ経由のキャストをしていたりunionを使うものが紹介されることがありますが、これらは未定義動作なのでだまされないように。

投稿2019/04/09 16:38

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2019/04/10 14:26

memcpyだとOKで、ポインタでキャストやunionはダメ、というあたり詳しく教えていただけませんか。
pepperleaf

2019/04/10 14:46 編集

memcpy()で、32bit 変数から、16bitx2 配列にコピーするのと、32bit変数のアドレス取って、(short *) でのキャストは同じです。(memcpy()の方がコピー分、遅い) また、union否定すると過去の多くのコードがアウトになりませんか? ただ、データ長の異なる変数混在の場合は、要注意ですが。 --- 指摘のリンク、見ましたが、短時間では分からなかった。ただ、回答の通りだとすると、過去のコードの多くが、NGとなると思う。
yumetodo

2019/04/10 15:06 編集

unionを使うのはCでは合法ですがC++では違法です。キャストは常にアウトです。 memcpyのコストを気にされているようですが、最適化で吹き飛びますのでご安心を。それよりも未定義動作を避けるべきです。
yumetodo

2019/04/10 15:26 編集

だからよく見るけど騙されないように、と書いたわけです。 strict aliasing rulesはその翻訳記事を書いた人ですら完全理解に至らないらしいので、極めて難しいでしょうね。(私も分からん)
yumetodo

2019/04/10 15:05

C++20ではもっとシンプルにstd::bit_castが導入されたのでそれでもいいですね。
thkana

2019/04/10 15:17

今回のお題は上位/下位16bitをそれぞれ取り出すことであって、上位/下位ワードを交換したものを得ようということではないので、紹介頂いたstrict aliasingの件には該当しないような気がしますが違うのでしょうか? 「壊れたコード」であっても、 uint32_t acopy=a; uint16_t *ptr=(uint16_t*)&acopy; としたときにptr[0]とptr[1]には(どっちがどっちかはともかく)上位/下位が得られていますよね。
thkana

2019/04/10 15:20

(strict aliasing rule 自体については知らなかったので大変参考になりました。最適化恐るべし。)
yumetodo

2019/04/10 15:23 編集

確かに読み取りだけなら大丈夫なので(ほんとか???)せめてconst uint16_t*にキャストしてあげてほしい。
yumetodo

2019/04/10 15:21

strict aliasing rules難しすぎでは・・・
yumetodo

2019/04/10 15:27 編集

ところでですね、恐ろしいことに気がついたんですが、少なくともC++17より前では、他の方が書いているshift演算を使う方法を符号付き整数型に対して行い、かつ中身が負の数だった場合、処理系依存になる気がする。(2の補数の保証がない) ・・・いや、ならないか、処理系依存になるbitは捨ててるもんな・・・。 夜中に回答するとろくなことにならん。
pepperleaf

2019/04/11 14:32

符号付の右シフト演算、Javaだと、符号ビットを拡張(?)してました。(2の割り算。仕様みたい) C/C++ は、、未確認。自分で使う場合は、正数か、符号無ししか使わなかったので、気が付かなかった。 memcpyのコピーコストの件は、同じことするなら、コピー分、余分でしょ、の意味です。 なお、昔、使った Cコンパイラは、そのまま使うと、レジスタ割当てで、アドレス取ると、メモリに割当て。ちゃんと使い分けてた。
yumetodo

2019/04/12 01:47

>コピー分、余分でしょ、の意味です。 コピーごと吹き飛ばした生成になることも。 https://godbolt.org/z/4KV4C5 適当な例が浮かばなかったのでサンプルが雑ですが、コンパイラはかなりのケースでmemcpyの呼び出しを吹き飛ばせる印象です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問