developer tip

C ++에서 C로 이동

optionbox 2020. 10. 8. 07:56
반응형

C ++에서 C로 이동


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

임베디드 분야에서 C ++를 무시하는 것이 옳고 그른지에 대한 질문을 제쳐두고 C ++에는 몇 가지 기능 / 관용구가 있습니다. 몇가지 말하자면:

  • 일반 형식이 안전한 데이터 구조 (템플릿 사용).
  • RAII. 특히 여러 리턴 포인트가있는 함수에서, 예를 들어 각 리턴 포인트에서 뮤텍스를 해제하는 것을 기억할 필요가 없습니다.
  • 일반적으로 소멸자. 즉, MyClass에 대해 d' tor를 한 번 작성하면 MyClass 인스턴스가 MyOtherClass의 구성원 인 경우 MyOtherClass는 MyClass 인스턴스를 명시 적으로 초기화 할 필요가 없습니다. 해당 d' tor는 자동으로 호출됩니다.
  • 네임 스페이스.

C ++에서 C로 전환 한 경험은 무엇입니까?
좋아하는 C ++ 기능 / 관용구를 대체하는 C는 무엇입니까? C ++에 원하는 C 기능을 발견 했습니까?


임베디드 프로젝트에서 작업하면서 모든 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);

많은 사람들이 아마 괜찮다고 말 하겠지만 한 줄에 두 번 이상의 "방법"호출을해야한다면 우스꽝스러워집니다. 두 줄의 C ++는 80 자 줄 길이 제한으로 인해 C의 다섯 줄로 바뀝니다. 둘 다 동일한 코드를 생성하므로 대상 프로세서가 신경 쓰지 않습니다!

한 번은 (1995 년에) 다중 프로세서 데이터 처리 프로그램을 위해 많은 C를 작성하려고했습니다. 각 프로세서에 자체 메모리와 프로그램이있는 종류입니다. 공급 업체가 제공 한 컴파일러는 C 컴파일러 (일종의 HighC 파생물) 였고 라이브러리는 폐쇄 된 소스 였기 때문에 GCC를 사용하여 빌드 할 수 없었으며 API는 프로그램이 주로 초기화 / 프로세스가 될 것이라는 사고 방식으로 설계되었습니다. / 종결 다양성, 그래서 프로세서 간 통신은 기껏해야 초보적이었습니다.

포기하기 약 한 달 전에 cfront 복사본을 찾아서 C ++를 사용할 수 있도록 makefile에 해킹했습니다. Cfront는 템플릿도 지원하지 않았지만 C ++ 코드는 훨씬 더 명확했습니다.

일반 형식이 안전한 데이터 구조 (템플릿 사용).

C가 템플릿에 가장 가까운 것은 다음과 같은 많은 코드로 헤더 파일을 선언하는 것입니다.

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

그런 다음 다음과 같이 가져옵니다.

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

첫 번째 unsigned char를 만들지 않는 한 복합 유형 (예 :의 대기열 없음)에서는 작동하지 않습니다 typedef.

아, 그리고이 코드가 실제로 어디에도 사용되지 않는다면 구문 상 올바른지조차 알지 못합니다.

편집 : 한 가지 더 : 코드 인스턴스화 수동으로 관리 해야 합니다. "템플릿"코드가 모두 인라인 함수 가 아닌 경우 , 링커가 "다중 Foo 인스턴스"오류를 뱉어 내지 않도록 한 번만 인스턴스화되도록 일부 제어를해야합니다. .

이렇게하려면 헤더 파일의 "구현"섹션에 인라인되지 않은 항목을 넣어야합니다.

#ifdef implementation_##TYPE

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

#endif

그런 다음 템플릿 변형 당 모든 코드의 위치에서 다음 을 수행해야합니다.

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

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

네, 추악하게 빠르게됩니다. 그래서 대부분의 C 프로그래머는 시도조차하지 않습니다.

RAII.

특히 여러 리턴 포인트가있는 함수에서, 예를 들어 각 리턴 포인트에서 뮤텍스를 해제하는 것을 기억할 필요가 없습니다.

음, 예쁜 코드를 잊고 (함수의 끝 제외) 모든 반환 지점에 익숙해 goto들 :

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는 MyClass 인스턴스를 명시 적으로 초기화 할 필요가 없습니다. 해당 d' tor는 자동으로 호출됩니다.

객체 생성은 동일한 방식으로 명시 적으로 처리되어야합니다.

네임 스페이스.

실제로 수정하기는 간단 합니다. 모든 기호에 접두사를 붙이기 만하면 됩니다 . 이것이 제가 이전에 이야기했던 소스 팽창의 주된 원인입니다 (클래스는 암시 적 네임 스페이스이기 때문에). C 사람들은 이것을 영원히 살았고 아마도 큰 문제가 무엇인지 알지 못할 것입니다.

YMMV


나는 다른 이유로 (알레르기 반응의 일종) C ++에서 C로 옮겼고, 내가 놓친 몇 가지와 내가 얻은 몇 가지만 있습니다. C99를 고수한다면, 가능하다면 아주 멋지고 안전하게 프로그래밍 할 수있는 구조가 있습니다. 특히

  • 지정된 이니셜 라이저 (결국 매크로와 결합 됨)는 간단한 클래스를 생성자처럼 쉽게 초기화합니다.
  • 임시 변수에 대한 복합 리터럴
  • for-scope 변수는 범위 바운드 리소스 관리 를 수행하는 데 도움이 될 수 있습니다 . 특히 예비 함수 반환에서도 unlock뮤텍스 또는 free배열 을 보장 합니다.
  • __VA_ARGS__ 매크로를 사용하여 함수에 대한 기본 인수를 갖고 코드 언 롤링을 수행 할 수 있습니다.
  • inline 오버로드 된 함수를 대체하기 위해 잘 결합 된 함수 및 매크로

Nothing like the STL exists for C.
There are libs available which provide similar functionality, but it isn't builtin anymore.

Think that would be one of my biggest problems... Knowing with which tool I could solve the problem, but not having the tools available in the language I have to use.


The difference between C and C++ is the predictability of the code's behavior.

It is a easier to predict with great accuracy what your code will do in C, in C++ it might become a bit more difficult to come up with an exact prediction.

The predictability in C gives you better control of what your code is doing, but that also means you have to do more stuff.

In C++ you can write less code to get the same thing done, but (at leas for me) I have trouble occasionally knowing how the object code is laid out in memory and it's expected behavior.


In my line of work - which is embedded, by the way - I am constantly switching back & forth between C and C++.

When I'm in C, I miss from C++:

  • templates (including but not limited to STL containers). I use them for things like special counters, buffer pools, etc. (built up my own library of class templates & function templates that I use in different embedded projects)

  • very powerful standard library

  • destructors, which of course make RAII possible (mutexes, interrupt disable, tracing, etc.)

  • access specifiers, to better enforce who can use (not see) what

I use inheritance on larger projects, and C++'s built-in support for it is much cleaner & nicer than the C "hack" of embedding the base class as the first member (not to mention automatic invocation of constructors, init. lists, etc.) but the items listed above are the ones I miss the most.

Also, probably only about a third of the embedded C++ projects I work on use exceptions, so I've become accustomed to living without them, so I don't miss them too much when I move back to C.

On the flip side, when I move back to a C project with a significant number of developers, there are whole classes of C++ problems that I'm used to explaining to people which go away. Mostly problems due to the complexity of C++, and people who think they know what's going on, but they're really at the "C with classes" part of the C++ confidence curve.

Given the choice, I'd prefer using C++ on a project, but only if the team is pretty solid on the language. Also of course assuming it's not an 8K μC project where I'm effectively writing "C" anyway.


Couple of observations

  • Unless you plan to use your c++ compiler to build your C (which is possible if you stick to a well define subset of C++) you will soon discover things that your compiler allows in C that would be a compile error in C++.
  • No more cryptic template errors (yay!)
  • No (language supported) object oriented programming

Pretty much the same reasons I have for using C++ or a mix of C/C++ rather than pure C. I can live without namespaces but I use them all the time if the code standard allows it. The reasons is that you can write much more compact code in C++. This is very usefull for me, I write servers in C++ which tend to crash now and then. At that point it helps a lot if the code you are looking at is short and consist. For example consider the following code:

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; 
}

In C that looks like:

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; 
}

Not a world of difference. One more line of code, but that tends to add up. Nomally you try your best to keep it clean and lean but sometimes you have to do something more complex. And in those situations you value your line count. One more line is one more thing to look at when you try to figure out why your broadcast network suddenly stops delivering messages.

Anyway I find that C++ allows me to do more complex things in a safe fashion.


I think the main problem why c++ is harder to be accepted in embedded environment is because of the lack of engineers that understand how to use c++ properly.

Yes, the same reasoning can be applied to C as well, but luckily there aren't that many pitfalls in C that can shoot yourself in the foot. C++ on the other hand, you need to know when not to use certain features in c++.

All in all, I like c++. I use that on the O/S services layer, driver, management code, etc. But if your team doesn't have enough experience with it, it's gonna be a tough challenge.

I had experience with both. When the rest of the team wasn't ready for it, it was a total disaster. On the other hand, it was good experience.

참고URL : https://stackoverflow.com/questions/4058496/moving-from-c-to-c

반응형