source

클랜 포맷이 내 코드를 깨뜨릴 수 있습니까?

ittop 2023. 9. 24. 13:05
반응형

클랜 포맷이 내 코드를 깨뜨릴 수 있습니까?

~하듯이clang-format코드를 다시 포맷하기 위한 도구인데, 이러한 포맷이 작동 코드를 깨거나 최소한 작동 방식을 변경할 수 있습니까?코드의 작동 방식을 바꿀 수 없는 어떤 종류의 계약이 있습니까?

는 가 많습니다.clang-format 줄들이 이라는 것을 의미합니다 이것은 코드의 많은 줄이 바뀔 것이라는 것을 의미합니다.A로가 없습니다.clang-format이 프로세스를 크게 단순화할 수 있습니다.

저는 그렇게 말할 거예요.clang-format코드의 작동 방식은 변경되지 않습니다.그러나 이것이 보장될 수 있을지 100% 확신할 수는 없습니다.

단답: 예.


clang-format도구가 있습니다.-sort-includes선택. 순서 #include명령어는 기존 코드의 동작을 확실히 바꿀 수 있고, 기존 코드를 깰 도 있습니다.

SortIncludes옵션이 다음으로 설정됩니다.true몇가지 된 스타일로 해,도 있습니다.clang-format포함 항목을 다시 정렬할 것입니다.

마이 스트럭트.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;
}

고정 스타일 .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이 이기 때문에 빈 줄로 히 d"되었지만,되었습니다.MyStruct.h표준 라이브러리가 다음을 포함하기 전에 이동되는 것으로부터.


하지만..

#include명령어는 코드를 파괴합니다. 어쨌든 다음 중 하나를 수행해야 합니다.

  1. 헤더 파일의 각 헤더에 대한 종속성을 명시적으로 포함합니다.제 예를 들어, 저는 다음과 같은 것을 포함해야 합니다.stdint.h인에MyStruct.h.

  2. 포함 그룹 사이에 주문 종속성을 명시적으로 나타내는 주석 줄을 추가합니다.하세요가 아닌 사람은비...#include라인은 그룹을 분할해야 하므로 댓글 라인도 작동합니다.줄합니다를 합니다.clang-format…을 MyStruct.h표준 라이브러리 헤더 앞에 표시됩니다.

대체-original.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;
}

확실히 코드가 작동하는 방식을 바꿀 수 있습니다.그리고 그 이유는 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

부터.clang-format는 을 미치므로다 할 수 .clang-formating은 공백까지 동일합니다.B스/B서 SD에서는SD/OS X할 수 .diff그리고.tr다음의 경우:

$ diff --ignore-all-space <(tr '\n' ' ' < 2.c ) <(tr '\n' ' ' < 1.c)

1.c:

#include <stdio.h>
int main() {printf("Hello, world!\n"); return 0;}

2.c:

#include <stdio.h>
int main() {
    printf("Hello, world!\n");
    return 0;
}

diff다. 이는 파일을 의미합니다.1.c그리고.2.c공백까지 동일합니다.

Karoly가 그의 코멘트에서 언급했듯이, 이상적인 조건에서는 문자열 리터럴과 같이 여전히 중요한 공간을 확인해야 합니다.하지만 현실 세계에서는 이 시험이 충분하다고 생각합니다.

프로젝트에서 재포맷된 ASM 코드를 클랜 형식으로 변경한 것은 다음과 같은 효과적인 작업을 수행했기 때문입니다.

#define ASM _asm

ASM {

  ...

}

네.

작업 흐름을 끊지 않을 것입니다.

시스템에 "C_Cpp.clang_format_sortIncludes"라는 구성 스위치가 있습니다. false. 그러나 작동하지 않습니다. 무엇이 문제인지 모르겠습니다.

버전은:ms-vscode.cpptools-0.13.1입니다.

이것이 제 해결책입니다.

안정적인 작업 흐름을 위해 문법을 사용합니다.

// 철썩철썩 떨어지다

...여기 당신의 코드가 있습니다.

// 에 딱 달라붙는.

코드와 서식 설정에 특수 구문을 사용하면 코드가 끊어질 수 있습니다.

인라인 어셈블러

일반적으로 gcc로 코드를 컴파일하고 gcc 스타일 인라인 어셈블러를 사용한다면, clang-format은 %-문자를 연산자로 보기 때문에 레지스터 변수의 이름을 깰 가능성이 매우 높습니다.

asm_movq(%[val2], %%mm0)

로 다시 포맷됩니다.

asm_movq(% [val2], % % mm0)

더 이상 컴파일할 수 없습니다.

매크로에서 경로 구성

문자열을 사용하지 않고 매크로를 사용하여 경로를 구축하면 clang-format은 다시 '/' 문자를 연산자로 보고 그 주위에 공백을 둡니다.

예를 들어, 부스트는 다음과 같은 컨스트럭트를 사용합니다.

#   define AUX778076_PREPROCESSED_HEADER \
    BOOST_MPL_CFG_COMPILER_DIR/BOOST_MPL_PREPROCESSED_HEADER

헤더 파일에 대한 경로를 구성합니다.'/'은(는) 여기서 연산자가 아니지만 문자열 안에 없기 때문에 clang-format은 연산자로 취급하고 그 주변에 공백을 두므로 다른 경로를 만듭니다.헤더 파일의 포함은 분명히 실패할 것입니다.

결론

네, 클랑 포맷은 코드를 깨뜨릴 수 있습니다.에지 케이스이거나 언어 표준을 벗어나거나 단순히 특정 컴파일러(clang이 아닌) 확장자인 매우 특정 구문을 사용하는 경우에는 clang-format에 의해 변경된 내용을 확인해야 합니다.그렇지 않으면 숨겨진 오류가 발생할 위험이 있습니다.

, 도입니다온rclang-format, 오늘 저는 이 문제에 직면했습니다.저의 사용 사례는 버그에 설명된 것과 유사했습니다.

int main() {
  int x = 0;
  int y = 0;
  return x < y - 1 >> 1;
}

다음과 같이 다시 포맷할 수 있습니다.

int main() {
  int x = 0;
  int y = 0;
  return x < y - 1 > > 1; /*<< Code is broken*/
}

다행히 수리가 되었고, 툴 업데이트가 도움이 되었습니다!

클랑의 정적 분석에 기반을 두고 있기 때문에 단순히 텍스트만으로 작동하는 바보 같은 소스 코드 포맷터(컴파일러 라이브러리를 사용할 수 있다는 것 중 하나)가 아니라 코드 자체의 구조에 대한 지식을 가지고 있기 때문에 그렇지 않을 것이라고 생각합니다.포맷터가 컴파일러 자체와 동일한 파서와 렉서를 사용한다는 점을 고려하면, 당신이 입력한 것과 동일하게 동작하는 코드를 뱉어내는 데 문제가 없을 만큼 충분히 안전하다고 생각합니다.

C++ 포맷의 소스 코드는 여기 http://clang.llvm.org/doxygen/Format_8cpp_source.html 에서 확인할 수 있습니다.

언급URL : https://stackoverflow.com/questions/37927553/can-clang-format-break-my-code

반응형