C では & を使用してレジスタ変数のアドレスを見つけることはできませんが、C++ では同じことができます。C++では合法なのにCでは合法でないのはなぜですか? 誰かがこの概念を詳しく説明してください。
8 に答える
これは、 C99標準(pdf)のセクション6.7.1(脚注101)からの抜粋です。
register
実装は、任意の宣言を単に宣言として扱うことができauto
ます。ただし、アドレス指定可能なストレージが実際に使用されているかどうかに関係なく、ストレージクラス指定子レジスタで宣言されたオブジェクトの任意の部分のアドレスは、&
明示的に( 6.5.3.2で説明した単項演算子を使用して)または暗黙的に(によって)計算できません。 6.3.2.1で説明されているように、配列名をポインタに変換します。したがって、storage-class指定子で宣言された配列に適用できる唯一の演算子register
はですsizeof
。
そして、セクション7.1.1、C ++標準のパラグラフ3(pdf)から:
指定子は、そのように宣言されたオブジェクトが頻繁に使用されるという実装へのヒントとともに
register
、指定子と同じセマンティクスを持っています。[注:ヒントは無視できます。ほとんどの実装では、オブジェクトのアドレスが取得された場合、ヒントは無視されます。—エンドノート]auto
についての楽しい一口register
C ++グループ(WG21)は非推奨にしたいと考えていregister
ます:
キーワードは
register
ほとんど機能せず、メモが通常無視されるというヒントしか提供しません。このバージョンの標準では非推奨になり、予約された名前を将来の標準で使用できるように解放しますauto
。これは、今回同様に役に立たないために再利用されたのと同じです。2009年3月の会議からのメモ:
CWGのコンセンサスは、非推奨にすることに賛成でした
register
。
C99グループ(WG14)が会議で(pdf)について言ったことを見てください。register
「<code>auto」キーワードを廃止する一般的な合意。以前の「<code>register」(アドレスなし)の使用に戻るようにWG21に依頼する必要がありますか?いいえ、これはWG21では飛行しません。
register キーワードは単なるヒントであり、無視できます。ほとんどの C++ コンパイラは常にそれを無視しますが、変数のアドレスを取得するか、変数への参照を作成すると、C++ コンパイラはそれを無視します。
一方、C++ コンパイラは、変数のアドレスを取得するという理由だけで「レジスタ」を無視する必要はありません。理論的には、コンパイラーはそれをレジスターに格納し、舞台裏で何らかの形でレジスターにマップされる魔法のポインター値を提供できますが、それはほとんど利益を得るために多くの作業を必要とするため、コンパイラーはありません (私が知っている)そのようなことは何でもします。
register は C でも無視できるので、レジスタ変数のアドレスを取得することを明示的に禁止したのは、これをチェックする C コンパイラの負担を軽減するためだけだったのではないかと思います。
C++ 標準の関連部分は 7.1.1.3 です。
register 指定子は auto 指定子と同じセマンティクスを持ち、そのように宣言されたオブジェクトが頻繁に使用されるという実装へのヒントを伴います。[注: ヒントは無視できます。ほとんどの実装では、オブジェクトのアドレスが取得された場合は無視されます。—終わりのメモ]
超遅い回答でごめんなさい。
問題は、C ではregister
もともとレジスタに値を格納することを意味していたため、レジスタint
にchar
使用できることです。しかし、時間の経過とともに、特に標準の C++ では、「CPU のレジスタ内」ではなく「高速アクセス」に拡大されました。したがって、C++ では、配列はregister
型である可能性がありますが、配列を CPU レジスタに格納することはできないことがわかっています。したがって、(上記の意味で) C++ レジスタをアドレス指定することは論理的に問題ありませんが、値が実際に CPU レジスタにある場合は意味がありません。
レジスタ変数にはアドレスがなく、CPUレジスタに保持されます(少なくとも保持されることになっています)。レジスタ修飾子はヒントにすぎないため、コンパイラにアドレスを抽出するコードを生成させると、修飾子は無視され、通常の変数がメモリに保持されます。
質問に直接答えるには、レジスタ変数のアドレスを取得できる方(元の投稿はそれ自体と矛盾しています)を使用すると、独自のヒントを無視でき、少なくとも警告を発行する必要があります。IMOの正しい実装は、レジスタ変数のアドレスの取得を禁止することです。
覚えておくべき重要なことは、「レジスタ」はコンパイラへのヒントにすぎないということです (これは意味のないものです。速度の向上は見たことがなく、ほとんどのコンパイラはおそらくそれを無視しています)。C と C++ はどちらも、「アドバイス」を無視して変数をメモリに保持することができます。もちろん、変数のアドレスを取得すると、メモリ内のスポットが強制的に割り当てられます。
C と C++ では、言語が異なるため、できることに関する規則が異なります。C++ の設計者は、レジスタ変数のアドレスを取得できるようにすることにしました。Cでは、メモリに強制されるため、これを行うことはできません。
もっと考えてみると、C の制限はおそらく、ブロックの先頭で変数を宣言しなければならなかったのと同じ理由によるものです。コンパイラは、変数が後で関数内でどのように使用されるかに関係なく、変数に遭遇したときに変数のメモリをレイアウトできます。
CとC++は2つの異なる言語であり、大きな共通のサブセットがあります。そのため、それらの間でいくつかの点が異なります。
私はあなたの質問を理解していませんが、register
(少なくともC ++では)変数がより頻繁にアクセスされる可能性があるというヒントであり、それ以上のものではありません。Cでは、単項演算子でアドレスを取得できないことを意味します&
。これは、その時点である程度意味がありました。Cの初期には、コンパイラが変数にメモリを割り当てる必要がないことが予想されていたため、必ずしもアドレスを取得する必要はありませんでした。
(コンピューターには通常、CPUのクイックアクセス部分であるレジスターがあり、アクセスするのに最速のストレージです。パフォーマンスが向上する場合は、変数がメモリーではなくレジスターに存在する可能性があります。)
現在、ほとんどすべてのコンパイラーは、プログラマーよりも優れた独自の割り当てを行うのに十分なほど洗練されているため、register
ほとんどの場合、使用しても意味がありません。
これは知識に基づいた推測にすぎませんが、C ++でレジスタのアドレスを取得できるとは思えません。そのような考えは、単に存在しないからです。C ++は、特定のケースではおそらくレジスタを使用しません。ストレージクラス修飾子register
はコンパイラへのヒントにすぎないことに注意してください(そして、すべてではないにしてもほとんどの最新のコンパイラはそれを完全に無視します)。