8

次のことを考慮してください。

volatile uint32_t i;

gccがiを揮発性として処理したかどうかを知るにはどうすればよいですか?近くのコードがそれを変更することはなく、何らかの割り込みが原因で変更される可能性があるため、そのように宣言されます。

私は世界最悪のアセンブリプログラマーではありませんが、テレビで再生しています。誰かがそれがどのように異なるかを理解するのを手伝ってもらえますか?

次の愚かなコードを取る場合:

#include <stdio.h>
#include <inttypes.h>

volatile uint32_t i;

int main(void)
{
        if (i == 64738)
                return 0;
        else
                return 1;
}

それをオブジェクト形式にコンパイルし、objdumpを介して逆アセンブルし、「volatile」を削除した後に同じことを行います。違いはありません(diffによる)。揮発性宣言は、チェックまたは変更された場所に近すぎますか、それとも揮発性を宣言するときに常に何らかのアトミックタイプを使用する必要がありますか?いくつかの最適化フラグはこれに影響しますか?

注意してください、私の愚かなサンプルは私の質問と完全には一致していません、私はこれを理解しています。私はgccが変数を揮発性として処理したかどうかを調べようとしているだけなので、違いを見つけるために小さなダンプを調べています。

4

7 に答える 7

14

状況によっては、多くのコンパイラが volatile を本来の方法で処理しません。厄介な驚きを避けるために、揮発性を多く扱う場合は、このペーパーを参照してください。また、標準からの引用に裏打ちされた volatile のかなり適切な説明も含まれています。

100% 確実なように、このような単純な例については、アセンブリの出力を確認してください。

于 2009-03-13T13:05:09.140 に答える
12

ループの外側で変数を設定し、ループの内側で読み取ってみてください。不揮発性の場合、コンパイラーはそれをレジスターに押し込むか、ループの前にコンパイル時定数または何かにする可能性があります (または変更しない可能性があります)。これは、変更されないことを「知っている」ためです。ループのたびに変数空間から読み取ります。

基本的に、何かを揮発性として宣言すると、特定の最適化を行わないようにコンパイラーに指示します。これらの最適化を行わないことにした場合、揮発性であると宣言されたために実行しなかったこと、または単に他の目的のためにそれらのレジスタが必要であると判断したこと、またはそれが変わる可能性があることに気付かなかったことがわかりません。それをコンパイル時定数に変換します。

于 2009-03-13T13:03:53.853 に答える
6

私の知る限り、volatile はオプティマイザーに役立ちます。たとえば、コードが次のようになっているとします。

int foo() {
    int x = 0;
    while (x);
    return 42;
}

「while」ループはバイナリから最適化されます。

しかし、'x' を volatile (つまりvolatile int x;) として定義すると、コンパイラはループをそのままにしておきます。

于 2009-03-13T13:05:56.360 に答える
5

あなたの小さなサンプルは、何かを示すには不十分です。volatile 変数とそうでない変数の違いは、コード内の各ロードまたはストアが volatile 変数の実行可能ファイルに正確に 1 つのロードまたはストアを生成する必要があることです。 -揮発性変数。サンプルで i が 1 回読み込まれている場合、それは揮発性と不揮発性に期待されることです。

違いを示すには、冗長なロードやストアが必要になります。次のようなものを試してください

int i = 5;
int j = i + 2;
i = 5;
i = 5;
printf("%d %d\n", i, j);

不揮発性と揮発性の間で i を変更します。違いを確認するには、ある程度の最適化を有効にする必要がある場合があります。

そこのコードには i の 3 つのストアと 2 つのロードがあり、i が揮発性でない場合は、1 つのストアとおそらく 1 つのロードに最適化できます。i が volatile と宣言されている場合、最適化に関係なく、すべてのストアとロードがオブジェクト コードに順番に表示されます。そうでない場合は、コンパイラのバグがあります。

于 2009-03-13T13:50:50.870 に答える
4

誤って引用したり反対票を投じたりする前に、標準をお読みください。以下は n2798 からの引用です。

7.1.6.1 cv 修飾子

7 注: volatile は、オブジェクトの値が実装によって検出できない方法で変更される可能性があるため、オブジェクトを含む積極的な最適化を回避するための実装へのヒントです。詳細なセマンティクスについては、1.9 を参照してください。一般に、volatile のセマンティクスは、C++ でも C と同じになるように意図されています。

キーワードvolatileはヒントとして機能します。registerキーワードによく似ています。ただし、volatileすべての最適化を控えるようコンパイラーに要求します。このようにして、変数のコピーをレジスタまたはキャッシュに保持せず (アクセス速度を最適化するため)、要求するたびにメモリからフェッチします。

混乱が非常に多いため、もう少し。実際、C99標準では、他の人が指摘しているように、volatile修飾されたオブジェクトを読み取るたびに検索する必要があると述べています。しかし、揮発性アクセスを構成するものは実装定義であると言う別のセクションもあります。したがって、ハードウェアを裏返しに知っているコンパイラは、たとえば、自動揮発性修飾変数があり、そのアドレスが取得されない場合、それがメモリの機密領域に配置されず、ほぼ確実に無視されることを認識します。ヒントを最適化して削除します。

このキーワードは、エラー処理の使用法setjmpとタイプを検出します。longjmp心に留めておかなければならない唯一のことは、変数が変更される可能性があると思われるときに volatile キーワードを指定することです。つまり、通常のオブジェクトを使用して、いくつかのキャストで管理できます。

心に留めておくべきもう 1 つのことは、揮発性アクセスを構成するものの定義は、標準では実装に残されているということです。

最適化を使用して別のアセンブリをコンパイルしたい場合

于 2009-03-13T13:04:35.007 に答える
4

常に揮発性として扱う必要があります。

コードが同じである理由は、volatile が、変数にアクセスするたびにメモリから変数をロードするようにコンパイラに指示するだけだからです。最適化がオンになっていても、コンパイラはコンパイル時に i の値を推測できないため、記述したコードでメモリから i をロードする必要があります。繰り返しアクセスすると違いがわかります。

于 2009-03-13T13:06:02.727 に答える