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

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

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

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

Q&A

解決済

3回答

1318閲覧

関数の戻り値が符号拡張されてしまう

kanedayo

総合スコア8

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

コンパイラ

コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

0グッド

2クリップ

投稿2021/11/15 06:56

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

godbolt.orgというサイトを知り、
いろいろなコンパイラがあるのだなと、興味深く操作していたところ、
コンパイラによって、結果が異なる現象を確認しました。→ 結果A/結果B

このような動作になるのは正しいのでしょうか?
何が起きているのか、興味があります。
同様の興味を抱いていただきありがとうございます。

C

1#include <stdint.h> 2uint64_t u32UL(void) 3{ 4 uint32_t u32 = 0x80000000u; 5 return ((u32)); 6 //return ((uint64_t)(u32)); 7 //return ((uint64_t)(uint32_t)(u32)); 8 9 // 結果A: +2147483648 = 0x80000000 (期待する戻り値) 10 // 結果B: -2147483648 = 0xFFFFFFFF80000000 11}

参考リンク https://godbolt.org/z/K4bKjnEaq

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

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

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

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

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

otn

2021/11/15 16:20 編集

確認方法が書いてないので、なんとも言いがたいですが、 u32UL()==0xFFFFFFFF80000000 が真になるかどうかで確認したと言うことですか?
kanedayo

2021/11/16 00:56

コメントありがとうございます。 参考リンク先で、先のコードを実行して確認しました。 同じコードでも、異なる定数を返すバイナリが生成されました。 実際に「u32UL()==0xFFFFFFFF80000000」を実行して確認したわけではございません。 実際に実行しても、そうなるようにしか思えないのですが、 期待する動作は「u32UL()==0x80000000」なので、 理由は分からないのですが、何かしらのカラクリがあるのだろう予感しています。
guest

回答3

0

参考リンク先で、先のコードを実行して確認しました。

同じコードでも、異なる定数を返すバイナリが生成されました。
実際に「u32UL()==0xFFFFFFFF80000000」を実行して確認したわけではございません。

なるほど。実行して確認しておらず、コンパイル結果のアセンブラコードを見たということですね。
(面白いサイトですね)
armアーキテクチャを知らないので、w0 と x0 についてググってみると、x0 が64bitレジスタで、w0 がその下位32bitのようです。
で、w0に値をロードするとx0の上位32bitはクリアされるようです。

ということで、mov w0, #-2147483648mov x0, 2147483648は同じ結果と思われます。
0x80000000を32bit整数表現したら負号が付いたんでしょう。

投稿2021/11/16 01:20

otn

総合スコア84498

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

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

kanedayo

2021/11/16 12:22

再度コメントいただきありがとうございます。 数ある変数の中のひとつとしか見ていませんでしたが、 w0 と x0 にこそ 重要な意味があることに 気付くことが出来ました。 コンパイラがレジスタの副作用(?)を活用している場面に立ち会えて、感動しました。 お付き合いいただき、ありがとうございました。 C言語としては、unsigned宣言しているので、本来なら符号拡張ではなく、0ビット拡張されて欲しいところです。これもまた、コンパイラがどちらでも結果が同じだとわかっているからだと、理解しました。
guest

0

ベストアンサー

64bit armでは、w0レジスタは64bitレジスタx0の下位32bitで、w0に書けば上位はゼロ拡張されるんだから、mov w0,-2147483648は結局x0=0x8000’0000になる。結局は同じ意味のコード。
When a W register is written,…,the top 32 bits of the 64-bit register are zeroed.

投稿2021/11/15 11:29

編集2021/11/15 11:38
matukeso

総合スコア1590

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

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

kanedayo

2021/11/16 11:42

お返事遅くなり申し訳ございません。 リンク先の挿絵付きの説明がわかりやすかったです。 アセンブリコードを読むときは、コード中の値だけではなく、 格納されている変数の仕様にも注意が必要だと理解できました。 ありがとうございました。 ※頂いたリンクがたどれない場合があったので、こちらでも再掲します。 https://developer.arm.com/documentation/102374/0101/Registers-in-AArch64---general-purpose-registers
guest

0

そういう挙動は正しくない、ですが、往々にして制限事項としてコンパイラのマニュアルに載ってたりしますね

投稿2021/11/15 07:38

y_waiwai

総合スコア87747

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

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

kanedayo

2021/11/16 12:49

コメントいただきありがとうございます。 本当に不思議な現象です。 C言語としては、unsigned宣言しているので、64ビットに拡張するならば、 符号拡張ではなく、0ビット拡張されて欲しいとこです。 素直に、32bit定数として扱うか、 64bitに符号拡張して、最後に32bit変数に格納することで帳尻をとるか、 コンパイラにも独特のクセがあることを知ることが出来ました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問