programing

C++에서 C로의 이행

goodsources 2022. 8. 31. 22:52
반응형

C++에서 C로의 이행

몇 년 동안 C++로 코딩한 후, 저는 최근 임베디드 분야의 C에서 코딩 작업을 제안받았습니다.

임베디드 필드에서 C++를 해제하는 것이 옳은지 그른지에 대한 질문은 차치하고라도 C++에는 많은 기능/이념이 있습니다.몇 가지 예를 들자면:

  • 범용 타입 세이프 데이터 구조(템플릿 사용)
  • RAII. 특히 여러 개의 리턴 포인트가 있는 기능에서는 각 리턴 포인트에서 뮤텍스를 해제할 필요가 없습니다.
  • 일반적으로 파괴자들입니다.즉, MyClass에 대해 d'tor를 한 번 쓰면 MyClass 인스턴스가 MyOtherClass의 멤버인 경우 MyOtherClass 인스턴스의 초기화를 명시적으로 해제할 필요가 없으며 자동으로 d'tor가 호출됩니다.
  • 네임스페이스

C++ C는 C++로 되어 있나요?
마음에 드는 C++ 기능/이름을 대체하기 위해 어떤 C를 찾았습니까?C++는 C++는?

다른 이유(알레르기 반응 등)로 C++에서 C로 옮겼는데 그리운 점과 얻은 점이 몇 가지 있습니다.만약 당신이 C99를 고수한다면, 가능하다면, 당신이 꽤 훌륭하고 안전하게 프로그래밍할 수 있게 해주는 구조들이 있습니다, 특히.

  • 지정된 이니셜라이저(결국 매크로와 결합됨)를 통해 컨스트럭터만큼 간단한 클래스의 초기화가 용이함
  • 임시 변수에 대한 복합 리터럴
  • forscope 변수에서는 특히 다음 사항을 확실하게 하기 위해 scope bound resource management를 수행할 수 있습니다.unlock 또는 뮤텍스free 시에도
  • __VA_ARGS__하고 코드 할 수 .
  • inline잘 및

임베디드 프로젝트를 하면서 올 C에서 한 번 작업해 보았지만 참을 수 없었습니다.너무 장황해서 아무것도 읽기 힘들었다. 저는 제가 매립용 에 들었습니다. 이는 훨씬 덜하고 고치기 . 그것은 훨씬 덜 안전하고 고치기 어려운 것으로 바뀌어야 했습니다.#define★★★★★★ 。

C++의 코드는 다음과 같습니다.

if(uart[0]->Send(pktQueue.Top(), sizeof(Packet)))
    pktQueue.Dequeue(1);

다음과 같이 변환됩니다.

if(UART_uchar_SendBlock(uart[0], Queue_Packet_Top(pktQueue), sizeof(Packet)))
    Queue_Packet_Dequeue(pktQueue, 1);

많은 사람들이 괜찮다고 하겠지만 한 번에 두세 통 이상의 전화를 해야 한다면 말도 안 되는 일이 될 것이다.2줄의 C++는 5줄의 C가 됩니다(80줄의 길이 제한으로 인해).둘 다 같은 코드를 생성하기 때문에 대상 프로세서에 관심이 없습니다.

One time (back in 1995), I tried writing a lot of C for a multiprocessor data-processing program. The kind where each processor has its own memory and program. The vendor-supplied compiler was a C compiler (some kind of HighC derivative), their libraries were closed source so I couldn't use GCC to build, and their APIs were designed with the mindset that your programs would primarily be the initialize/process/terminate variety, so inter-processor communication was rudimentary at best.

I got about a month in before I gave up, found a copy of cfront, and hacked it into the makefiles so I could use C++. Cfront didn't even support templates, but the C++ code was much, much clearer.

Generic, type-safe data structures (using templates).

The closest thing C has to templates is to declare a header file with a lot of code that looks like:

TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{ /* ... */ }

then pull it in with something like:

#define TYPE Packet
#include "Queue.h"
#undef TYPE

컴파운드 타입에서는 동작하지 않는 것에 주의해 주세요(예를 들어 큐가 없는 경우).unsigned char를 작성하지 않는 한typedef첫번째.

Oh, and remember, if this code isn't actually used anywhere, then you don't even know if it's syntactically correct.

EDIT: One more thing: you'll need to manually manage instantiation of code. If your "template" code isn't all inline functions, then you'll have to put in some control to make sure that things get instantiated only once so your linker doesn't spit out a pile of "multiple instances of Foo" errors.

To do this, you'll have to put the non-inlined stuff in an "implementation" section in your header file:

#ifdef implementation_##TYPE

/* Non-inlines, "static members", global definitions, etc. go here. */

#endif

And then, in one place in all your code per template variant, you have to:

#define TYPE Packet
#define implementation_Packet
#include "Queue.h"
#undef TYPE

또한 이 구현 섹션은 표준을 벗어나야 합니다.#ifndef/#define/#endif템플릿 헤더 파일을 다른 헤더 파일에 포함할 수 있지만 나중에 템플릿 헤더 파일을 인스턴스화할 필요가 있기 때문에.c파일.

Yep, it gets ugly fast. Which is why most C programmers don't even try.

RAII.

Especially in functions with multiple return points, e.g. not having to remember to release the mutex on each return point.

Well, forget your pretty code and get used to all your return points (except the end of the function) being gotos:

TYPE * Queue_##TYPE##_Top(Queue_##TYPE##* const this)
{
    TYPE * result;
    Mutex_Lock(this->lock);
    if(this->head == this->tail)
    {
        result = 0;
        goto Queue_##TYPE##_Top_exit:;
    }

    /* Figure out `result` for real, then fall through to... */

Queue_##TYPE##_Top_exit:
    Mutex_Lock(this->lock);
    return result;
}

일반적으로 파괴자들입니다.

즉, MyClass에 대해 d'tor를 한 번 쓰면 MyClass 인스턴스가 MyOtherClass의 멤버인 경우 MyOtherClass 인스턴스의 초기화를 명시적으로 해제할 필요가 없으며 자동으로 d'tor가 호출됩니다.

오브젝트 구축은 명시적으로 같은 방법으로 처리되어야 합니다.

네임스페이스

그것은 사실 수정하기 쉬운 것입니다: 모든 기호 에 접두사를 붙이기만 하면 됩니다.이것이 앞에서 설명한 소스 블러트의 주요 원인입니다(클래스는 암묵적인 네임스페이스이기 때문입니다).C씨네들은 평생 이런 생활을 해왔고, 아마 뭐가 대단한지 모를거야.

YMMV

C 에 STL c c c 。
비슷한 기능을 제공하는 libs가 있지만 더 이상 내장되어 있지 않습니다.

그게 내 가장 큰 문제 중 하나일 것 같은데...어떤 툴을 사용하여 문제를 해결할 수 있는지 알고 있지만 사용할 수 있는 언어로 된 도구가 없습니다.

C와 C++의 차이는 코드 동작의 예측 가능성입니다.

C에서는 코드가 무엇을 할지를 매우 정확하게 예측하는 것이 더 쉽고, C++에서는 정확한 예측을 하는 것이 조금 더 어려워질 수 있습니다.

C의 예측 가능성은 코드 동작을 더 잘 제어할 수 있지만 더 많은 작업을 수행해야 한다는 것을 의미합니다.

C++에서는 같은 작업을 수행하기 위해 코드를 적게 쓸 수 있지만, (나로서는) 오브젝트 코드가 메모리에 어떻게 배치되어 있는지, 그리고 그것이 예상되는 동작인지 알기 어려울 때가 있습니다.

덧붙여서, 제 업무 라인에서는, C와 C++를 항상 왔다 갔다 하고 있습니다.

C에 있을 때는 C++가 그립습니다.

  • 템플릿(STL 컨테이너 포함, 이에 한정되지 않음)특수 카운터, 버퍼 풀 등(각종 임베디드 프로젝트에서 사용하는 클래스 템플릿 및 함수 템플릿의 라이브러리를 구축)에 사용합니다.

  • 매우 강력한 표준 라이브러리

  • 파괴자(RAII를 가능하게 하는 것) (뮤텍스, 인터럽트 비활성화, 트레이스 등

  • 액세스 지정자, 누가 무엇을 사용할 수 있는지(표시할 수 없음)를 보다 적절하게 적용하기 위해

저는 대규모 프로젝트에서 상속을 사용하고 있으며, C++의 임베디드 지원은 기본 클래스를 첫 번째 멤버로 내장하는 C "핵"보다 훨씬 깨끗하고 좋습니다(컨스트럭터의 자동 호출, init은 말할 것도 없습니다).목록 등)을 참조할 수 있지만, 위의 항목들은 제가 가장 그리워하는 항목들입니다.

또, 사용하고 있는 임베디드형 C++프로젝트의 3분의 1 정도 밖에 되지 않기 때문에, 사용하지 않는 생활에 익숙해졌기 때문에, C로 돌아와도 그다지 그리워하지 않습니다.

반대로 개발자가 많은 C프로젝트로 돌아가면 C++의 모든 문제를 사람들에게 설명하는 데 익숙해져 있습니다.대부분 C++의 복잡성으로 인한 문제이며, 무슨 일이 일어나고 있는지 알고 있다고 생각하는 사람들은 C++ 신뢰 곡선의 "C with classes" 부분에 있습니다.

선택권이 주어지면, 저는 프로젝트에 C++를 사용하는 것을 선호합니다만, 그 언어에 대해 팀이 꽤 확실한 경우에만요.또한 8K μC 프로젝트가 아니라고 가정하고, 어쨌든 효과적으로 "C"를 쓰고 있습니다.

몇 가지 관찰

  • C++ 컴파일러를 사용하여 C를 빌드할 계획이 없는 한(C++의 잘 정의된 서브셋을 고수할 경우 가능) 컴파일러가 C++에서 허용하는 컴파일 오류인 것을 곧 발견할 수 있습니다.
  • 더 이상 암호화 템플릿 오류는 없습니다(Yay!).
  • (언어 지원) 객체 지향 프로그래밍 없음

순수한 C가 아닌 C++ 또는 C/C++를 혼합한 것과 거의 같은 이유를 가지고 있습니다.네임스페이스 없이도 살 수 있지만 코드 표준이 허락한다면 항상 네임스페이스를 사용합니다.그 이유는 C++로 훨씬 더 콤팩트한 코드를 쓸 수 있기 때문입니다.이것은 매우 유용하게 쓰입니다.저는 가끔 크래쉬 하는 서버를 C++로 씁니다.이 때 보고 있는 코드가 짧고 일관성이 있으면 도움이 됩니다.예를 들어 다음 코드를 생각해 보겠습니다.

uint32_t 
ScoreList::FindHighScore(
  uint32_t p_PlayerId)
{
  MutexLock lock(m_Lock); 

  uint32_t highScore = 0; 
  for(int i = 0; i < m_Players.Size(); i++)
  {
    Player& player = m_Players[i]; 
    if(player.m_Score > highScore)
      highScore = player.m_Score; 
  }

  return highScore; 
}

C에서는 다음과 같이 보입니다.

uint32_t 
ScoreList_getHighScore(
  ScoreList* p_ScoreList)
{
  uint32_t highScore = 0; 

  Mutex_Lock(p_ScoreList->m_Lock); 

  for(int i = 0; i < Array_GetSize(p_ScoreList->m_Players); i++)
  {
    Player* player = p_ScoreList->m_Players[i]; 
    if(player->m_Score > highScore)
      highScore = player->m_Score; 
  }

  Mutex_UnLock(p_ScoreList->m_Lock);

  return highScore; 
}

전혀 다르지 않다.한 줄의 코드가 더 있지만, 앞뒤가 맞는 경향이 있어요일반적으로 당신은 그것을 깨끗하고 희박하게 유지하기 위해 최선을 다하지만 때로는 더 복잡한 것을 해야 한다.이러한 상황에서는 회선 수가 중요합니다.브로드캐스트네트워크가 갑자기 메시지 전달을 정지하는 이유를 파악하려고 할 때 한 줄 더 살펴봐야 할 것이 있습니다.

어쨌든 C++를 사용하면 더 복잡한 작업을 안전하게 수행할 수 있습니다.

임베디드 환경에서 c++가 받아들여지기 어려운 주된 문제는 c++의 사용법을 제대로 이해하는 엔지니어가 부족하기 때문이라고 생각합니다.

네, C에게도 같은 논리가 적용될 수 있지만, 다행히 C에는 자신의 발을 쏠 수 있는 함정이 그리 많지 않습니다.한편, C++ 에서는, c++ 의 특정의 기능을 사용하지 않는 타이밍을 알 필요가 있습니다.

전체적으로 저는 c++를 좋아합니다.O/S 서비스 계층, 드라이버, 관리 코드 등에서 사용하고 있습니다.하지만 그쪽 팀이 충분한 경험이 없다면, 어려운 도전이 될 거예요.

둘 다 경험했어요.나머지 팀원들이 준비가 안 됐을 때, 그것은 완전히 실패였다.한편으로, 그것은 좋은 경험이었다.

그래! 나는 이 두 언어를 모두 경험했고 C++가 더 친근한 언어라는 것을 알게 되었어.더 많은 기능을 지원합니다.C++는 C 언어에서 실제로 지원되지 않는 다형성, 인터랙스, 연산자 및 함수 오버로드, 사용자 정의 데이터 유형 등의 추가 기능을 제공하기 때문에 C 언어의 슈퍼셋이라고 하는 것이 좋습니다.C에서 C++로 이동하는 주된 이유인 객체 지향 프로그래밍의 도움으로 코드의 수천 행이 몇 행으로 줄어듭니다.

언급URL : https://stackoverflow.com/questions/4058496/moving-from-c-to-c

반응형