35

コードを再フォーマットするだけのツールであるように、そのclang-formatようなフォーマットは動作中のコードを壊したり、少なくとも動作を変えたりする可能性はありますか? コードの動作を変更する/変更できないというある種の契約はありますか?

でフォーマットしたいコードがたくさんありますclang-format。これは、多くのコード行が変更されることを意味します。原因によってのみ変更されたコードのすべての行を確認するclang-format必要がないことは、このプロセスを大幅に簡素化します。

clang-formatコードの仕組みは変わらないと思います。一方で、これが保証できるかどうかは 100% 確信が持てません。

4

7 に答える 7

73

簡単な答え: はい。


clang-formatツールにはオプションがあり-sort-includesます。ディレクティブの順序を変更する#includeと、既存のコードの動作が確実に変更され、既存のコードが壊れる可能性があります。

対応するSortIncludesオプションがいくつかの組み込みスタイルによって設定されているため、インクルードの順序が変更さtrueれるかどうかは明らかではありません。clang-format

MyStruct.h:

struct MyStruct {
    uint8_t value;
};

オリジナル.c:

#include <stdint.h>
#include <stddef.h>
#include "MyStruct.h"

int main (int argc, char **argv) {
    struct MyStruct s = { 0 };
    return s.value;
}

では、 を実行するとしましょうclang-format -style=llvm original.c > restyled.c

restyled.c:

#include "MyStruct.h"
#include <stddef.h>
#include <stdint.h>

int main(int argc, char **argv) {
  struct MyStruct s = {0};
  return s.value;
}

ヘッダー ファイルの並べ替えが原因で、コンパイル時に次のエラーが発生しますrestyled.c

In file included from restyled.c:1:
./MyStruct.h:2:5: error: unknown type name 'uint8_t'
    uint8_t value;
    ^
1 error generated.

ただし、この問題は簡単に回避できます。このような順序依存のインクルードがある可能性は低いですが、そうする場合は、特定の順序を必要とするヘッダーのclang-formatグループの間に空白行を入れることで問題を解決できます。の間に。#include#include

固定オリジナル.c:

#include <stdint.h>
#include <stddef.h>

#include "MyStruct.h"

int main (int argc, char **argv) {
    struct MyStruct s = { 0 };
    return s.value;
}

fixed-restyled.c:

#include <stddef.h>
#include <stdint.h>

#include "MyStruct.h"

int main(int argc, char **argv) {
  struct MyStruct s = {0};
  return s.value;
}

stdint.hと のインクルードはまだ「グループ化」されているため、とstddef.hはまだ並べ替えられていることに注意してください。ただし、新しい空白行MyStruct.hは標準ライブラリのインクルードの前に移動できませんでした。


でも...

ディレクティブの順序を変更する#includeとコードが壊れる場合は、とにかく次のいずれかを実行する必要があります。

  1. 各ヘッダーの依存関係をヘッダー ファイルに明示的に含めます。私の例では、に含める必要がありstdint.hますMyStruct.h

  2. インクルード グループの間に、順序の依存関係を明示的に示すコメント行を追加します。非行#includeはグループを分割する必要があるため、コメント行も同様に機能することに注意してください。次のコードのコメント行も、標準ライブラリ ヘッダーの前にインクルードできないようにclang-formatします。MyStruct.h

代替オリジナル.c:

#include <stdint.h>
#include <stddef.h>
// must come after stdint.h
#include "MyStruct.h"

int main (int argc, char **argv) {
    struct MyStruct s = { 0 };
    return s.value;
}
于 2016-06-23T18:21:47.193 に答える
11

確かに、コードの動作を変更できます。その理由は、C プログラムがそのソース コードのいくつかのプロパティを表示できるからです。私が考えているのは__LINE__マクロですが、他に方法がないかどうかはわかりません。

考慮してください1.c

#include <stdio.h>
int main(){printf("%d\n", __LINE__);}

それで:

> clang 1.c -o 1.exe & 1.exe
2

今いくつかを行いますclang-format

> clang-format -style=Chromium 1.c >2.c

そして2.c、次のとおりです。

#include <stdio.h>
int main() {
  printf("%d\n", __LINE__);
}

そしてもちろん、出力が変更されました。

> clang 2.c -o 2.exe & 2.exe
3
于 2016-06-21T06:44:24.097 に答える
-5

それはclangの静的分析に基づいて構築されているため、テキストだけで動作する単なる愚かなソースコードフォーマッターではなく、コード自体の構造に関する知識を持っていることを考えると、そうはならないと思います(できることの恩恵の1つ)コンパイラ ライブラリを使用します)。フォーマッタがコンパイラ自体と同じパーサーとレクサーを使用することを考えると、フィードしたものと同じように動作するコードを吐き出す問題が発生しないほど十分に安全だと思います。

C++ フォーマッタのソース コードは、http: //clang.llvm.org/doxygen/Format_8cpp_source.htmlで確認できます。

于 2016-06-20T16:43:08.403 に答える