programing

C++ 컴파일러로 C 코드를 컴파일할 때 어떤 문제를 예상할 수 있습니까?

padding 2023. 7. 12. 22:18
반응형

C++ 컴파일러로 C 코드를 컴파일할 때 어떤 문제를 예상할 수 있습니까?

만약 당신이 기존의 C 코드 베이스를 가지고 C++ 컴파일러로 컴파일한다면, 어떤 종류의 문제가 발생할 것으로 예상할 수 있습니까?예를 들어 열거형 값에 정수를 할당하는 것은 C++에서는 실패하지만 C에서는 합법적입니다.

C로 extern C { ... }내가 가장 예상하지 못한 곳에서 이름을 더럽힐까요?제가 정말 이러면 안 되는 이유가 있나요?

배경으로, 우리는 C로 작성된 매우 큰 코드 기반을 참조하십시오.몇 년 동안 우리는 C++(예를 들어 홈브루 상속)를 통해 자연스럽게 발생할 수 있는 일들을 하기 위해 노력해 왔습니다.우리는 C++을 향해 점진적으로 나아가기 시작하고 싶습니다. CORBA와 같은 프레임워크를 통해 이를 지원하고 C++이 제공하는 보다 자연스러운 접근 방식을 활용하기 위해 모듈을 리팩터링합니다.

저는 이런 일을 한 적이 있습니다.문제의 주요 원인은 당신이 의심한 것처럼 C++이 유형에 대해 더 엄격하다는 것입니다.void*가 다른 유형의 포인터와 혼합된 캐스트를 추가해야 합니다.메모리 할당과 마찬가지로:

Foo *foo;
foo = malloc(sizeof(*foo));

위는 일반적인 C 코드이지만 C++로 캐스트해야 합니다.

Foo *foo;
foo = (Foo*)malloc(sizeof(*foo));

C++에는 "class", "and", "boole", "catch", "delete", "explicit", "mutable", "namespace", "new", "operator", "or", "private", "protected", "friend" 등의 새로운 예약어가 있습니다.예를 들어 변수 이름으로 사용할 수 없습니다.

C++ 컴파일러로 오래된 C 코드를 컴파일할 때 가장 일반적인 문제는 위와 같습니다.비호환성에 대한 전체 목록은 ISO C와 ISO C++ 간의 비호환성을 참조하십시오.

당신은 또한 이름 망글링에 대해 묻습니다.외부 "C" 래퍼가 없는 경우 C++ 컴파일러는 기호를 망칩니다.C++ 컴파일러만 사용하고 dlsym()이나 라이브러리에서 기호를 끌어오기 위해 의존하지 않는 한 문제가 되지 않습니다.

모든 비호환성에 대한 매우 자세한 목록은 ISO C와 ISO C++ 간의 비호환성을 참조하십시오.컴파일러 오류로 즉시 나타나지 않는 문제를 포함하여 많은 미묘한 문제가 있습니다.예를 들어 문제가 될 수 있는 한 가지 문제는 문자 상수의 크기입니다.

// In C, prints 4.  In C++, prints 1
printf("%d\n", sizeof('A'));

모든 C 파일을 "external C { ... }"(외부 C { ... })로 래핑하지 않으면 예상치 못한 곳에서 이름을 더럽힐 수 있습니까?

당신이 C와 C++를 연결하려고 할 때 그것은 당신을 괴롭힙니다.

다음을 포함하는 많은 헤더 파일을 작성했습니다.

#ifdef __cplusplus
    extern "C" {
#endif

// rest of file

#ifdef __cplusplus
    }
#endif

잠시 후 기존 다중 포함 보일러 플레이트로 병합되고 표시되지 않습니다.그러나 일반적으로 머리글이 포함된 후에는 해당 항목이 포함에 주의해야 합니다.

제가 정말 이러면 안 되는 이유가 있나요?

만약 당신이 C와 C++를 결합하지 않을 것이라는 것을 확실히 안다면, 제가 알고 있는 것처럼 그렇게 할 이유가 없습니다.그러나 당신이 설명한 점진적인 마이그레이션을 통해 C 구성 요소와 C++ 구성 요소가 모두 사용해야 하는 게시된 인터페이스가 있는 모든 경우에 필수적입니다.

이렇게 하지 않는 가장 큰 이유는 기능을 오버로드하는 것을 방지하기 때문입니다(적어도 이러한 헤더의 경우).모든 코드를 C++로 마이그레이션하고 유지보수/리팩터링/확장을 시작한 후에는 이 작업을 수행할 수 있습니다.

일반적으로, 당신은 전혀 문제를 겪지 않을 것입니다.네, C와 C++ 사이에 비호환성이 몇 가지 있지만, 위에서 언급한 malloc 캐스팅을 제외하고는 그렇게 자주 나오지 않는 것 같습니다. 이는 수정하기에 매우 사소한 것입니다.

다음 오픈 소스 C 라이브러리를 C++로 성공적으로 컴파일하여 사용했습니다.

  • Expat XML 파서
  • FreeType2 글꼴 래스터라이저
  • libjpeg: JPEG 이미지 처리
  • libpng: PNG 이미지 처리
  • Zlib 압축 라이브러리

가장 어려운 부분은 네임스페이스 래퍼를 추가하는 것이었는데, 몇 시간이 걸렸습니다. 주로 #include 문이 C++ 네임스페이스 외부에 있어야 했기 때문입니다.

내가 왜 이런 짓을 했을까요?왜냐하면 저는 사람들이 그들의 앱에 직접 연결되어 있는 상업용 라이브러리를 판매하기 때문입니다. 그리고 때때로 그들의 앱은 다른 버전의 Expat, FreeType 등과 연결되어 있었습니다.이로 인해 다중 정의 기호 오류가 발생했습니다.가장 깨끗한 작업은 라이브러리 내의 모든 것을 이동하여 네임스페이스에 숨기는 것이었습니다.

하지만, 저는 제가 사용하는 모든 오픈 소스 라이브러리에서 그렇게 하지 않았습니다.몇몇은 아직 갈등을 일으키지 않았고, 저는 그것들을 고칠 여유가 없었습니다. 비록 문제가 없는 것이 꽤 지루하긴 하지만요.흥미로운 예외는 C++로 컴파일할 수 없었던 SQLite입니다.그래서 저는 외부에서 볼 수 있는 모든 기호에 접두사(제품 이름)를 추가하여 대대적인 검색과 교체를 했습니다.그것으로 제 고객의 문제가 해결되었습니다.

또 다른 예는 C++에서는 int에서 enum으로 암묵적인 변환이 없는 반면, C에서는 하나의 변환이 있습니다.C++로 정말 하고 싶다면 깁스가 필요할 것입니다.

MSVC를 사용하기 전에 이 작업을 수행한 적이 있습니다. MSVC를 사용하는 것이 좋은 전략이라면 다음과 같습니다.

  1. CPP로 빌드할 개별 파일을 설정하면 CPP 컴파일러로 점진적으로 이동할 수 있습니다.
  2. ctrl+f7을 사용하여 하나의 파일을 작성합니다.
  3. 모든 malloc를 캐스팅하는 대신 템플릿 버전을 생성할 수 있습니다.

foo = (Foo*)malloc(크기(*foo));

된다

foo = malloc<Foo>();

그리고 물론 Foo+n 바이트를 원하는 경우에는 과부하가 걸릴 수 있습니다.

또한 가능한 경우 메모리 할당을 RAII를 사용하도록 전환할 것을 권장합니다. RAII로 전환하는 것은 매우 복잡하기 때문에 위험이 너무 높다는 것을 알게 되었습니다. 대부분의 경우 그렇게 하기에 충분히 간단했습니다.

C++는 유형 검사가 엄격하기 때문에 각 호출에 malloc/realloc/calloc에 캐스트를 추가해야 할 수 있습니다.

C++ 컴파일러로 컴파일 시도:

typedef enum{ false = 0, true = 1} bool;

언급URL : https://stackoverflow.com/questions/861517/what-issues-can-i-expect-compiling-c-code-with-a-c-compiler

반응형