Table of Contents
Legacy C Code에 대한 이해
레거시 C 코드, 종종 수십 년 오래 된, 카운트리스 임베디드 시스템의 백본을 형성, 운영 체제 및 엔터프라이즈 응용. 이 코덱은 원래 제한된 메모리, 느린 프로세서 및 primitive 도구 체인의 제약 아래 작성되었다. 그들은 신뢰할 수 있지만, 그들은 일반적으로 문제의 호스트를 포트 : 모듈, 깊이 배열 된 조건, 마술 번호, 플랫폼 별 확장에 무거운 의존하는 글로벌 변수를 분산. 현대 재 공장, 이러한 코드는 하드웨어와 같은 강력한 행동을 유지하지 않고, 이러한 코드를 효율적으로 변환 할 수 있습니다.
이 웹 사이트는 귀하가 웹 사이트를 탐색하는 동안 귀하의 경험을 향상시키기 위해 쿠키를 사용합니다. 이 쿠키들 중에서 필요에 따라 분류 된 쿠키는 웹 사이트의 기본적인 기능을 수행하는 데 필수적이므로 브라우저에 저장됩니다. 또한이 웹 사이트의 사용 방식을 분석하고 이해하는 데 도움이되는 제 3 자 쿠키를 사용합니다. 이 쿠키는 귀하의 동의하에 만 브라우저에 저장됩니다. 이러한 쿠키를 거부 할 수도 있습니다. 이러한 쿠키 중 일부를 선택 해제하면 검색 환경에 영향을 미칠 수 있습니다.
효과적인 Refactoring를 위한 전략
다음 전략은 기존 C 코드를 현대화하기위한 체계적인 프레임 워크를 형성합니다. 각 접근법은 소프트웨어의 핵심 기능을 보존하면서 기술 부채를 감소시킵니다.
1. 종합적인 부호 감사를 실시하십시오
코드 감사는 정확한 통증 점을 식별합니다. 자동적으로 버그, 보안 취약점, 현대 코딩 표준의 위반을 감지하는 정적 분석 도구를 사용합니다. 예를 들어, Cppcheck은 null 포인터 디셉트, 버퍼 오버플로우 및 사용되지 않는 변수를 잡아줍니다. Clang Static Analyzer는 더 깊은 경로 감지 체크를 제공합니다. 이 도구는 변경 전에 이러한 변경 사항을 통해 변경하지 않고 변경된 도구가 도입되지 않습니다.
감사 중에는 빌드 시스템을 검사합니다. 현대화 Makefiles 또는 CMakeLists는 크로스 플랫폼 컴파일을 지원하며 와 같은 컴파일러 경고를 활성화합니다. 아키텍처를 문서화하고 의존성 그래프를 만들 수 있습니다. 이 모듈화 노력이 나중에 안내합니다.
2. 현대 기호화 기준 설치
코덱의 일관성을 가져다주는 인식 코딩 표준을 채택한다. MISRA C 지침 (자동차 및 안전 크리티컬 시스템에서 사용) 정의된 행동을 감소시키고 읽을 수 있습니다. 범용 프로젝트의 경우, 최신 C 표준에 따라 C11, 선호 C17을 준수합니다. 이것은 , 익명 구조 및 스레드 (C11)와 같은 기능을 제공합니다.
naming Conventions (e.g., ] 함수와 변수에 대한 ), indentation (tabs vs. space), 그리고 댓글 스타일 (Doxygen 또는 이와 유사한). ]clang-tidy를 통해 이러한 규칙을 강화하십시오.
3. 부호를 모듈화하십시오
레거시 C는 종종 수백 또는 수천 개의 라인에 걸쳐 모놀리식 기능을 포함합니다. 각각 하나의 일을하는 작은, 공동 함수로 끊습니다. 기본 인터페이스 및 소스 파일을 구현하기 위해 헤더 파일을 사용합니다. 예를 들어, 네트워크 및 파일 I / O를 분리 모듈 ]/] 및 /로 처리하는 파일을 나눕니다.
모듈화는 글로벌 변수를 줄입니다. 함수 인자 또는 pointers를 통해 전달된 로컬 상태와 같이 대체합니다. 이것은 신뢰할 수 있고 단위 테스트를 가능하게 합니다. 파일에서 정의 헤더에 있는 opaque type(forward 선언을 forward 선언합니다)을 도입하여 구현 세부 사항을 숨기도록 합니다.
// Before: monolithic, global state
int buffer[256];
int index = 0;
void process_data() { /* manipulates global buffer and index */ }
// After: encapsulated module
// buffer.h
typedef struct Buffer Buffer;
Buffer* buffer_create(size_t size);
int buffer_push(Buffer* b, int value);
void buffer_destroy(Buffer* b);
// buffer.c
struct Buffer {
int* data;
size_t size;
size_t index;
};
Buffer* buffer_create(size_t size) { ... }
4. Deprecated 및 Unsafe 기능을 대체하십시오
C 표준 라이브러리에는 현대 보안 코딩에서 탈취하거나 차별되는 여러 가지 불쾌한 기능을 포함합니다. 체계적으로 교체하십시오.
- ] →
- → 또는 ]
- → 또는 ]
- → ]
- → ]
- → ]
- → + ] 필드 폭 한계
이러한 변경은 버퍼 오버플로우, 보안 취약점의 주요 소스를 제거. 또한, 윈도우에서 를 정의하거나 오류로 탈선 기능을 치료하는 컴파일러 플래그를 사용하여 오래된 기능을 비활성화. SEI CERT C Coding Standard]는 안전한 대안의 종합적인 목록을 제공합니다.
5. 기억 관리 개량
레거시 C의 동적 메모리 할당은 종종 오류 프로입니다. 일반적인 문제는 무료 메모리, 이중 무료 및 dangling 포인터에 잊을 수 있습니다. 이러한 관행과 메모리 관리:
- ] 대신 ]를 0-initialized Memory가 필요합니다.
- 항상 에 할당 함수의 반환 값을 확인합니다.
- 할당을 추적하는 래퍼 기능을 생성 (예 : ] 실패에 낙관).
- 일관된 소유권 모델을 채택하십시오: 기능이있는 문서는 메모리를 소유하고 그것을 해방하는 책임입니다.
- Valgrind (Memcheck) 또는 AddressSanitizer(ASan)과 같은 도구를 사용하여 누출 및 아웃-of-bounds가 테스트 중에 액세스할 수 있습니다.
성능 크리티컬 섹션에서는 정적 버퍼 또는 앨리케이터를 사용하여 조각과 오버 헤드를 피하기 위해 고려합니다. 제약 메모리를 가진 임베디드 시스템을 위해 사전 할당 된 풀과 동적 할당을 대체합니다.
6. Safer Pointer 사용법을 채택합니다
포인터는 두 배 가장자리 칼입니다. 버그의 기회를 줄이기 위해 그들의 사용을 현대화:
- ] 함수 매개변수를 사용하여 수정되지 않은 함수를 사용합니다. 이 컨트랙트를 정리하고 컴파일러가 최적화된 것을 돕습니다.
- ] (C99 onward)로 별칭하지 않는 객체에 포인터를 할당합니다. 이것은 더 나은 벡터화가 가능합니다.
- 주조 unnecessarily. 바이트 스트림에서 읽을 때, use ] 대신 주조 대신 엄격한 별칭 위반을 방지합니다.
- undefined 동작을 방지하기 위해 제대로 typed 함수 포인터를 사용하여 함수 포인터 캐스트를 교체합니다.
- ] 대신 유연한 어레이 멤버(C99)를 사용하세요. (struct의 끝에 크기 배열).
// Avoid: casting void* to misaligned type
int value = *(int*)(byte_buffer + offset); // potential UB
// Prefer: memcpy
int value;
memcpy(&value, byte_buffer + offset, sizeof(value));
7. 개량 과실 취급
Legacy C는 종종 ], 반환 코드, 글로벌 오류 상태를 사용합니다. 오류 처리가 일관된 패턴으로 변경되지 않습니다. 옵션은 다음과 같습니다.
- 함수의 enumerated return type(e.g., ])을 사용합니다.
- 에러 코드에 대한 를 반환하지 마십시오. 서명된 정수는 오류에 대한 부정적인 값을 허용한다.
- 복잡한 시스템을 위해 ]/]를 사용하여 경량의 예외 핸들링 패턴을 구현합니다. (그러나 흐르는 컨트롤을 준수하는 것과 같이 sparingly를 사용합니다).
- 높은 수준의 오류를 로그하고 깨끗한 모든 손상된 리소스를 사용하여 ] 패턴 (judiciously) 반복적 인 정리 코드를 방지합니다.
8. Unit Test 도입
테스트없이, 재발견은 영감입니다. C의 단위 테스트 프레임 워크를 초기화하십시오. C의 인기있는 선택은 다음과 같습니다.
각 재발급 모듈에 대한 단위 테스트를 작성합니다. 테스트 기반 개발 (TDD)를 사용하여 태어날 수 있습니다. 원하는 행동을 정의하는 테스트를 작성하고 테스트 패스까지 다시 팩터를 다시 입력해야합니다. 통합 테스트는 알려진 입력 및 예상 출력으로 전체 시스템을 실행해야합니다. CI 환경에서 모든 테스트를 자동화하여 즉시 회귀를 잡을 수 있습니다.
9. 성과 고려
의 확장은 종종 성능 향상, 그러나 또한 오버 헤드를 소개 할 수 있습니다 (예, 더 많은 기능 호출, 메모리 할당 래퍼). 전에 프로파일 및 변경 후 도구 , ], 또는 Xcode 악기. 핫 경로에 초점 최적화. 기본 컴파일러 최적화 ( 또는 ) 및 아키텍처 특정 플래그 (]). 컴파일러의 기본 설정은 가능한 미래 유지 보수를 사용하여 가능한 유지 보수를 절약 할 수 있습니다.
시험 및 검증
단계별 테스트 전략은 레거시 코드를 재발견할 때 중요합니다. 이 단계를 따르십시오.
- Regression test – 기본 설정 변경 전에 기존 테스트 스위트를 실행합니다. 아무 테스트가 존재하지 않는 경우, 연기 테스트가 발생하면, 핵심 경로가 운동하는 연기 테스트를 작성합니다.
- Incremental validation – 한 번에 한 모듈을 다시 입력합니다. 각 변경 후, 엄격한 플래그와 실행 단위 테스트를 컴파일합니다. 작은 원자가로 버전 제어(예: Git)를 사용하여 쉽게 되돌릴 수 있습니다.
- Static analysis integration – Cppcheck와 clang-tidy를 CI 파이프라인에 추가합니다. 오류가 품질 시행으로 경고를 치료합니다.
- Dynamic analysis – Valgrind 또는 ASan 아래에서 재사용하여 메모리 문제를 재구성하는 것을 구축합니다.
- User Accept testing – 시효 환경에 재공장 시스템을 배포하고 도메인 전문가가 최종 승인을 수행. 원본과 출력 로그, 타이밍 및 리소스 사용 비교.
CI 서버(GitHub Actions, Jenkins, GitLab CI)와 함께 이러한 단계를 자동화하여 수동 오버 헤드를 줄이고 재발견 과정에서 신뢰를 구축합니다.
관련 기사
이 프로젝트는 프로젝트의 핵심 요소인 반면, 이 프로젝트는 프로젝트의 핵심 요소인 반면, 이 프로젝트는 프로젝트의 핵심 요소인 “이 프로젝트의 핵심 요소”를 의미하는 것입니다. 이 프로젝트는 프로젝트의 핵심 요소인 “이 프로젝트의 핵심 요소”를 의미하는 것입니다. 이 프로젝트는 프로젝트의 핵심 요소인 “이 프로젝트의 핵심 요소”를 기반으로 하는 프로젝트의 핵심 요소인 “이 프로젝트의 핵심 요소”를 개발하는 데 필요한 요소입니다. 이 프로젝트는 프로젝트의 핵심 요소인 “이 프로젝트의 핵심 요소”를 기반으로 하는 프로젝트의 핵심 요소입니다. 이 프로젝트는 프로젝트의 핵심 요소인 “이 프로젝트”를 의미하는 것입니다.