임베디드 개발을 위해 C ++ 대신 C를 사용하는 이유가 있습니까?


81

질문

하드웨어 C ++ 및 C89에 두 개의 컴파일러가 있습니다.

클래스와 함께 C ++를 사용하는 것에 대해 생각하고 있지만 (vtables를 피하기 위해) 다형성이 없습니다. C ++를 사용하고 싶은 주된 이유는 다음과 같습니다.

  • 매크로 정의 대신 "인라인"함수를 사용하는 것을 선호합니다.
  • 접두사가 코드를 복잡하게 만들 때 네임 스페이스를 사용하고 싶습니다.
  • 주로 템플릿과 장황한 캐스팅으로 인해 C ++가 약간 더 안전하다고 생각합니다.
  • 오버로드 된 함수와 생성자 (자동 캐스팅에 사용)를 정말 좋아합니다.

매우 제한된 하드웨어 (4kb RAM)를 개발할 때 C89를 고수 할 이유가 있습니까?

결론

답변 해 주셔서 감사합니다. 정말 도움이되었습니다!

나는 주제를 통해 생각했고 주로 다음과 같은 이유로 C를 고수 할 것입니다.

  1. C에서 실제 코드를 예측하는 것이 더 쉬우 며 4kb의 램만 있으면 정말 중요합니다.
  2. 우리 팀은 주로 C 개발자로 구성되어 있으므로 고급 C ++ 기능은 자주 사용되지 않습니다.
  3. 내 C 컴파일러 (C89)에서 함수를 인라인하는 방법을 찾았습니다.

좋은 답변을 너무 많이 제공했기 때문에 하나의 답변을 받아들이 기가 어렵습니다. 안타깝게도 위키를 만들고 수락 할 수 없으므로 가장 생각하게 만든 답변을 하나 선택하겠습니다.


11
한 가지 : 어떤 언어로 작성하는지 항상 완벽하게 명확하게하십시오. "C / C ++"로 프로그램을 작성하려고하지 마십시오. 사용할 언어 기능과 사용하지 않을 언어 기능을 알고 C로 작성하거나 C ++로 작성하십시오.
David Thornley


"임베디드 개발"정의
Marco van de Voort 2010-06-30

@DavidThornley, 당신은 임베디드 케이스에 적합 할 수 있지만, Kamailio와 같은 일반적인 산업 오픈 소스 앱을 STL로 확장하고자하는 곳에서 C와 C ++ 코드가 얼마나 잘 섞여 있는지에 대해 매우 놀랐습니다. 저는 STL 및 C 코드의 이러한 사용을 장려하고 있습니다. 이는 앞으로 엄청난 기능과 ​​유지 관리의 용이성을 제공하는 동시에 거의 제로 문제를 생성하기 때문입니다 (C ++에 포함 된 구조체의 부족은 C ++에 대한 끔찍한 범죄이며 최대한 빨리 해결해야합니다. ).
user2548100

생각할 거리가 있습니다. 여기 ZeroMQ의 설계자이자 작가가 왜 C 대신 C ++로 코드 기반을 작성하는 것을 후회하는지에 대해 논의하는 훌륭한 기사가 있습니다. 내가 예상 한 바가 전혀 아니고이 페이지의 다른 곳에서도 찾을 수없는 이유 때문입니다. 250bpm.com/blog:4
user2548100

답변:


48

C ++보다 C를 사용하는 두 가지 이유 :

  1. 많은 임베디드 프로세서의 경우 C ++ 컴파일러가 없거나 추가 비용을 지불해야합니다.
  2. 내 경험으로는 임베디드 소프트웨어 엔지니어의 상당수가 C ++에 대한 경험이 거의 없거나 전혀 없다는 것입니다. (1) 때문이거나 전자 공학 학위에 대한 교육을받지 않는 경향이 있기 때문입니다. 따라서 계속 사용하는 것이 좋습니다. 그들이 아는 것.

또한 원래 질문과 많은 의견에는 4Kb의 RAM이 언급되어 있습니다. 일반적인 임베디드 프로세서의 경우 RAM의 양은 코드가 저장되고 플래시에서 실행되므로 코드 크기와 관련이 없습니다.

확실히 코드 저장 공간의 양은 염두에 두어야 할 사항이지만, 새롭고 용량이 더 큰 프로세서가 시장에 등장함에 따라 가장 비용에 민감한 프로젝트를 제외하고는 예전보다 문제가 적습니다.

임베디드 시스템과 함께 사용하기 위해 C ++의 하위 집합 사용 : 이제 MISRA C ++ 표준이 있습니다.

편집 : 임베디드 시스템의 C 대 C ++에 대한 논쟁으로 이어진 이 질문 도 참조하십시오 .


2
아래의 더 긴 대답을 참조하십시오. C ++는 FLASH에 상수 데이터를 넣는 것을 매우 어렵게 만드는 경향이 있습니다.
jakobengblom2

3
C ++ 대신 C를 사용하는 좋은 이유는 C의 표준 ABI입니다. 완전성을 위해.
Chris Lutz

66

4KB의 RAM과 같이 리소스 가 매우 제한된 대상의 경우 순수한 ANSI C 구현으로 쉽게 다시 이식 할 수없는 많은 노력을 기울이기 전에 몇 가지 샘플로 물을 테스트했습니다.

임베디드 C ++ 워킹 그룹은 언어의 표준 하위 집합과 표준 라이브러리의 표준 하위 집합을 제안했습니다. 불행히도 C 사용자의 저널이 죽었을 때 그 노력을 잃어 버렸습니다. 거기에서 기사 것 같습니다 위키 백과 하고 있다고 위원회는 여전히 존재합니다.

임베디드 환경에서는 메모리 할당에주의해야합니다. 이러한 관리를 시행하려면 사용 operator new()되지 않음을 알 수 있도록 연결될 수없는 무언가에 전역 및 그 친구 를 정의해야 할 수 있습니다. new반면에 안정적이고 스레드 안전하며 지연 시간이 보장되는 할당 체계와 함께 신중하게 사용하면 배치 는 친구가 될 수 있습니다.

인라인 함수는 애초에 진정한 함수 여야 할만큼 충분히 크지 않는 한 많은 문제를 일으키지 않습니다. 물론 매크로를 대체하는데도 동일한 문제가있었습니다.

인스턴스화가 제대로 실행되지 않는 한 템플릿도 문제를 일으키지 않을 수 있습니다. 사용하는 템플릿에 대해 생성 된 코드 (링크 맵에 충분한 단서가있을 수 있음)를 감사하여 사용하려는 인스턴스화 만 발생했는지 확인하십시오.

발생할 수있는 또 다른 문제는 디버거와의 호환성입니다. 다른 방법으로 사용 가능한 하드웨어 디버거가 원본 소스 코드와의 상호 작용을 매우 제한적으로 지원하는 것은 드문 일이 아닙니다. 어셈블리에서 효과적으로 디버그해야하는 경우 C ++의 흥미로운 이름 변경으로 인해 작업에 추가 혼란이 추가 될 수 있습니다.

RTTI, 동적 캐스트, 다중 상속, 무거운 다형성 및 예외는 모두 사용에 대해 어느 정도의 런타임 비용과 함께 제공됩니다. 이러한 기능 중 일부는 사용되는 경우 전체 프로그램에 비해 비용이 많이 드는 수준이고 다른 일부는 필요한 클래스의 가중치를 증가시킵니다. 차이점을 알고 최소한 간단한 비용 / 이익 분석에 대한 완전한 지식을 가지고 고급 기능을 현명하게 선택하십시오.

작은 임베디드 환경에서는 실시간 커널에 직접 연결하거나 하드웨어에서 직접 실행합니다. 어느 쪽이든 런타임 시작 코드가 C ++ 특정 시작 작업을 올바르게 처리하는지 확인해야합니다. 이는 올바른 링커 옵션을 사용하는지 확인하는 것만 큼 간단 할 수 있지만 전원 켜기 재설정 진입 점에 대한 소스를 직접 제어하는 ​​것이 일반적이므로 모든 작업을 수행하는지 확인하기 위해 감사해야 할 수도 있습니다. 예를 들어 제가 작업 한 ColdFire 플랫폼에서 개발 도구는 C ++ 이니셜 라이저가 있지만 주석 처리 된 CRT0.S 모듈과 함께 제공되었습니다. 상자에서 바로 사용했다면 생성자가 전혀 실행되지 않은 전역 개체에 의해 미스터리되었을 것입니다.

또한 임베디드 환경에서는 하드웨어 장치를 사용하기 전에 초기화해야하는 경우가 많으며, OS 및 부트 로더가없는 경우이를 수행하는 것이 코드입니다. 전역 개체에 대한 생성자 는를 호출 하기 전에 실행 main()되므로 전역 생성자가 호출 되기 전에 하드웨어 초기화를 완료하려면 로컬 CRT0.S (또는 이에 상응하는 항목)를 수정해야합니다 . 분명히, 정상은 main()너무 늦었습니다.


1
이것은 내가 줄 수있는 것보다 더 많은 찬성표가 필요합니다! 훌륭한 대답입니다.
Harper Shelby

+1, 좋은 답변입니다. 하지만 정말 걱정할 필요가있는 유일한 템플릿 인스턴스화는 (상대적으로 드문) 재귀 유형이라고 생각합니다. "일반"비 재귀 유형의 경우 인스턴스화는 어쨌든 수동으로 입력 한 코드에 해당합니다.
j_random_hacker

2
@j_random_hacker, 사실. 그러나 템플릿의 습관은 사용 시점에서 적절한 유형 강제가이를 막았을 수있는 두 번째 (또는 세 번째) 인스턴스화가 나타날 때 가끔 놀라움으로 이어질 수 있습니다. 조심해야 할 것입니다.
RBerteig

@RBerteig : 좋은 점, 템플릿은 더 적은 유형 강제 변환 가능성을 허용합니다 => 템플릿이 아닌 코드보다 더 뚜렷한 인스턴스화가 생성 될 수 있습니다.
j_random_hacker

26

아니요. 문제를 일으킬 수있는 C ++ 언어 기능 (런타임 다형성, RTTI 등)은 임베디드 개발을 수행하는 동안 피할 수 있습니다. 임베디드 C ++ 개발자 커뮤니티가 있습니다 (예전 C / C ++ 사용자 저널에서 C ++를 사용하는 임베디드 개발자의 칼럼을 읽은 기억이 있습니다). 선택이 그렇게 나쁘다면 그들이 매우 목소리를 낼 것이라고 상상할 수 없습니다.


20

C ++ 성능에 대한 기술 보고서 는 이러한 종류의 훌륭한 가이드입니다. 임베디드 프로그래밍 문제에 대한 섹션이 있습니다!

또한 답변에서 Embedded C ++에 대한 언급에 대한 ++. 표준은 내 취향에 100 %는 아니지만 C ++의 어떤 부분을 떨어 뜨릴 지 결정할 때 좋은 참고 자료입니다.

소규모 플랫폼 용으로 프로그래밍하는 동안 예외 및 RTTI를 비활성화하고, 가상 상속을 피하고, 주변에있는 가상 기능의 수에 세심한주의를 기울였습니다.

그러나 당신의 친구는 링커 맵입니다. 자주 확인하면 코드 소스와 정적 메모리 팽창을 빠르게 발견 할 수 있습니다.

그 후에는 표준 동적 메모리 사용 고려 사항이 적용됩니다. 언급 한 것처럼 제한된 환경에서는 동적 할당을 전혀 사용하지 않는 것이 좋습니다. 때로는 작은 동적 할당을위한 메모리 풀이나 블록을 미리 할당하고 나중에 전체를 버리는 "프레임 기반"할당을 사용할 수 있습니다.


16

C ++ 컴파일러를 사용하는 것이 좋지만 C ++ 특정 기능의 사용을 제한합니다. C ++에서 C처럼 프로그래밍 할 수 있습니다 (대부분의 임베디드 애플리케이션에서는 어쨌든 표준 라이브러리를 사용하지 않지만 C ++을 수행 할 때 C 런타임이 포함됩니다).

계속해서 C ++ 클래스 등을 사용할 수 있습니다.

  • 가상 기능의 사용을 제한하십시오 (말한대로)
  • 템플릿 사용 제한
  • 임베디드 플랫폼의 경우 new 연산자를 재정의하거나 메모리 할당을 위해 new 배치를 사용하고 싶을 것입니다.

8
물론 이미 기본적으로 C를 작성하고 있다면 공식적으로 작성하는 것이 좋습니다.
Chuck

6
템플릿 사용을 제한하는 이유는 무엇입니까? 템플릿 함수는 예를 들어 루프를 풀기 위해 임베디드 시스템에서 정말 도움이 될 수 있다고 생각했습니다.
Piotr Czapla

1
여전히 템플릿을 사용할 수 있지만 출력 바이너리의 크기를 빠르게 늘릴 수 있으므로 매우주의해야합니다. 물론, 코드가 ROM 또는 이와 유사한 것에서 직접 실행되고 여분의 ROM 공간이있는 경우에는 물론 템플릿으로 수행하는 작업에주의해야합니다 (각 템플릿 인스턴스는 기본적으로 모든 템플릿 코드가 다시 복제됩니다). 최악의 경우 최종 실행 파일에서).
arke

14

펌웨어 / 임베디드 시스템 엔지니어로서 C가 여전히 C ++보다 1 위를 선택하는 이유 중 일부를 말씀 드릴 수 있으며, 두 가지 모두에 능통합니다.

1) 우리가 개발하는 일부 타겟에는 코드와 데이터 모두에 대해 64kB의 RAM이 있으므로 모든 바이트 수를 확인해야합니다. 예, 2 시간이 소요되는 4 바이트를 절약하기 위해 코드 최적화를 처리했습니다. 2008.

2) 모든 C 라이브러리 함수는 크기 제한으로 인해 최종 코드에 포함되기 전에 검토되므로 분할 (하드웨어 분할기가 없으므로 큰 라이브러리가 필요함), malloc (힙이 없기 때문에)을 사용하지 않는 것이 좋습니다. , 모든 메모리는 512 바이트 청크의 데이터 버퍼에서 할당되며 코드 검토를 거쳐야 함) 또는 큰 페널티를 수반하는 기타 객체 지향 방식입니다. 사용하는 모든 라이브러리 함수가 카운트된다는 것을 기억하십시오.

3) 오버레이라는 용어를 들어 본 적이 있습니까? 코드 공간이 너무 작아서 때때로 다른 코드 세트로 교체해야합니다. 라이브러리 함수를 호출하는 경우 라이브러리 함수가 상주해야합니다. 오버레이 함수에서만 사용하면 너무 많은 객체 지향 메서드에 의존하여 많은 공간을 낭비하게됩니다. 따라서 C ++는 물론 C 라이브러리 함수도 허용되지 않는다고 가정하지 마십시오.

4) 제한된 하드웨어 설계 (예 : 특정 방식으로 연결된 ECC 엔진)로 인해 또는 하드웨어 버그에 대처하기 위해 캐스팅 및 패킹 (정렬되지 않은 데이터 구조가 단어 경계를 넘는 경우)이 필요합니다. 당신은 너무 많은 것을 암시 적으로 가정 할 수 없습니다. 그런데 왜 객체가 그것을 너무 많이 지향 하는가?

5) 최악의 시나리오 : 객체 지향 방법 중 일부를 제거하면 폭발 할 수있는 리소스 (즉, 데이터 버퍼가 아닌 스택에 512 바이트 할당)를 사용하기 전에 개발을 생각하고 잠재적 인 최악의 시나리오를 방지 할 수 있습니다. 전체 코드 경로를 함께 테스트하거나 제거하지 않습니다.

6) 우리는 소프트웨어로부터 하드웨어를 유지하고 코드를 가능한 한 이식 가능하고 시뮬레이션 친화적으로 만들기 위해 많은 추상화를 사용합니다. 하드웨어 액세스는 서로 다른 플랫폼간에 조건부로 컴파일되는 매크로 또는 인라인 함수로 래핑되어야합니다. 데이터 유형은 특정 대상이 아닌 바이트 크기로 캐스팅되어야합니다. 직접 포인터 사용은 허용되지 않습니다 (일부 플랫폼에서는 메모리 매핑 된 I / O가 데이터 메모리와 동일) 등

나는 더 많이 생각할 수 있지만 당신은 아이디어를 얻습니다. 우리 펌웨어 담당자는 객체 지향 교육을 받았지만 임베디드 시스템의 작업은 하드웨어 지향적이고 낮은 수준 일 수 있으므로 본질적으로 높은 수준이거나 추상화 할 수 없습니다.

BTW, 내가했던 모든 펌웨어 작업은 소스 제어를 사용합니다. 어디서 그 아이디어를 얻었는지 모르겠습니다.

-SanDisk의 펌웨어 전문가.


90의 시작 부분에서 다시는, 오버레이는 매우 인기 (도스 세계에서 적어도) 기술이었다
psihodelia을

좋은 포인트 Shing. C ++는 기능이 제한되고 리소스가 훨씬 더 제한된 프로젝트에서 전화 부스에서 스모 선수처럼 느껴집니다.

4
나는이 답변이 매우 주관적이고 구체적인 추론을 제공하지 않는다고 생각합니다.
Venemo

1
C ++는 반드시 "객체 지향"을 의미 하지는 않습니다 .
마틴 보너 모니카 지원

1
임베디드 시스템의 작업이 본질적으로 추상화 할 수 없다는 것은 사실이 아닙니다. 포인트 6)에서 직접 말씀하셨습니다. "우리는 sw로부터 hw를 유지하고 코드를 가능한 한 이식성있게 만들기 위해 많은 추상화를 사용합니다.":-) BTW : "추상화"가 반드시 "다형성"을 의미하는 것은 아닙니다.
Daniele Pallastrelli

9

개인적으로 선호하는 것은 C입니다.

  • 모든 코드 줄이 무엇을하고 있는지 (및 비용) 알고 있습니다.
  • 나는 모든 코드 라인이 무엇을하고 있는지 (그리고 비용) 알만큼 C ++를 잘 모른다

사람들은 왜 이렇게 말합니까? asm 출력을 확인하지 않으면 C의 모든 행이 무엇을하는지 알 수 없습니다 . C ++도 마찬가지입니다.

예를 들어,이 무고한 문이 생성하는 asm은 다음과 같습니다.

a[i] = b[j] * c[k];

상당히 순진 해 보이지만 gcc 기반 컴파일러는 8 비트 마이크로 용으로이 asm을 생성합니다.

CLRF 0x1f, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1f, F, ACCESS
MOVWF 0x1e, ACCESS
MOVLW 0xf9
MOVF 0xfdb, W, ACCESS
ADDWF 0x1e, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfa
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1f, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x1c
NOP
MOVFF 0xfef, 0x1d
NOP
MOVLW 0x1
CLRF 0x1b, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1b, F, ACCESS
MOVWF 0x1a, ACCESS
MOVLW 0xfb
MOVF 0xfdb, W, ACCESS
ADDWF 0x1a, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfc
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1b, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x18
NOP
MOVFF 0xfef, 0x19
NOP
MOVFF 0x18, 0x8
NOP
MOVFF 0x19, 0x9
NOP
MOVFF 0x1c, 0xd
NOP
MOVFF 0x1d, 0xe
NOP
CALL 0x2142, 0
NOP
MOVFF 0x6, 0x16
NOP
MOVFF 0x7, 0x17
NOP
CLRF 0x15, ACCESS
RLCF 0xfdf, W, ACCESS
ANDLW 0xfe
RLCF 0x15, F, ACCESS
MOVWF 0x14, ACCESS
MOVLW 0xfd
MOVF 0xfdb, W, ACCESS
ADDWF 0x14, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfe
MOVF 0xfdb, W, ACCESS
ADDWFC 0x15, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0x16, 0xfee
NOP
MOVFF 0x17, 0xfed
NOP

생성되는 명령어의 수는 다음에 따라 크게 달라집니다.

  • a, b, c의 크기.
  • 해당 포인터가 스택에 저장되었는지 또는 전역인지 여부
  • i, j 및 k가 스택에 있는지 또는 글로벌인지 여부

이것은 프로세서가 C를 처리하도록 설정되지 않은 작은 임베디드 세계에서 특히 그렇습니다. 따라서 내 대답은 항상 asm 출력을 검사하지 않는 한 C와 C ++가 서로 나쁘다는 것입니다. 서로 똑같이 좋습니다.

휴고


2
또한 실제로 multiply 함수를 호출하는 모든 것의 중간에 호출 명령이 있습니다. 그 모든 코드는 곱셈 명령도 아닙니다!
Rocketmagnet

마이크로에 익숙한 사람은 일반적으로 C 코드의 각 부분을 분리하여 처리하는 간단한 방법을 알고있을 것이며, 괜찮은 컴파일러는 그보다 더 나쁜 코드를 생성해서는 안됩니다. 위의 표현식을 효율적으로 처리 할 수있는 유일한 방법은 C 컴파일러에 적합하지 않을 수있는 가정을하는 것입니다.
supercat

8

어떤 사람들은 더 간단하고 생성 될 실제 코드를 예측하기가 더 쉽기 때문에 임베디드 작업에 C를 선호한다고 들었습니다.

개인적으로 C 스타일의 C ++를 작성하면 (유형 안전성을위한 템플릿 사용) 많은 이점을 얻을 수 있다고 생각할 것이며 그렇지 않은 실제 이유를 볼 수 없습니다.


+1, 투명성은 항상 중요하며 (아마도) 제한된 디버깅 도구가있는 제한된 환경의 경우 더 그렇습니다.
j_random_hacker

7

C ++ 대신 C를 사용할 이유가 없습니다. C에서 할 수있는 것은 무엇이든 C ++에서도 할 수 있습니다. VMT의 오버 헤드를 피하려면 가상 방법과 다형성을 사용하지 마십시오.

그러나 C ++는 오버 헤드없이 매우 유용한 관용구를 제공 할 수 있습니다. 내가 가장 좋아하는 것 중 하나는 RAII입니다. 클래스는 메모리 나 성능 측면에서 비싸지 않아도됩니다 ...


6

IAR Workbench에서 ARM7 임베디드 paltform에 대한 코드를 작성했습니다. 컴파일 시간 최적화 및 경로 예측을 수행하기 위해 템플릿에 의존하는 것이 좋습니다. 전염병과 같은 동적 캐스팅을 피하십시오. Andrei Alexandrescu의 저서 Modern C ++ design에 명시된대로 특성 / 정책을 유리하게 사용하십시오 .

배우기가 어려울 수 있지만 귀사의 제품이이 접근 방식의 이점을 누릴 것이라고 확신합니다.


5

좋은 이유와 때로는 유일한 이유는 특정 임베디드 시스템에 대한 C ++ 컴파일러가 아직 없다는 것입니다. 예를 들어 Microchip PIC 마이크로 컨트롤러의 경우입니다. 작성하기가 매우 쉽고 무료 C 컴파일러 (실제로는 약간의 C 변형)가 있지만 C ++ 컴파일러가 보이지 않습니다.


1
Comeau Computing ( comeaucomputing.com )은 C로 컴파일되는 C ++ 컴파일러를 판매합니다.
Thomas L Holaday

3
으으. 그 사이트는 토하고 싶어했습니다.
shoosh

@shoosh : 예, 사이트 디자인이 끔찍합니다. 그러나 컴파일러 자체는 적어도 표준 적합성 측면에서이 분야의 리더로 간주됩니다 (성능에 대한 정보가 없습니다).
j_random_hacker

그 웹 사이트는 내가 살아 숨 쉬는 매우 화난 과일 샐러드에 갇혀있는 것처럼 느끼게합니다.
Tim Post

5

4K의 램으로 제한된 시스템의 경우 C ++가 아닌 C를 사용하여 진행중인 모든 것을 확인할 수 있습니다. C ++의 장점은 코드를 훑어 보는 것보다 훨씬 더 많은 리소스 (CPU와 메모리 모두)를 사용하기가 매우 쉽다는 것입니다. (오, 저는 다른 BlerfObject를 만들어서 그렇게 할 것입니다 ... 아! 메모리 부족!)

이미 언급했듯이 (RTTI, vtables 등) C ++에서 할 수 있지만 C에서 동일한 작업을 수행하는 것처럼 C ++ 사용이 벗어나지 않도록 많은 시간을 할애합니다. .


2
마지막 문장은 옳지 만 C ++는 균형을 잃을 수도있는 C보다 다른 이점을 제공하기 때문에 관련이 없습니다. Piotr은 이미 이러한 (제로 비용) 이점 중 일부를 언급했습니다.
Konrad Rudolph

5

인간의 마음은 가능한 한 많이 평가 한 다음 집중해야 할 중요한 사항을 결정하고 나머지는 버리거나 감가 상각하여 복잡성을 처리합니다. 이것은 마케팅, 그리고 주로 아이콘의 브랜딩이면의 전체 토대입니다.

이러한 경향에 맞서기 위해 저는 C ++보다 C를 선호합니다. 그 이유는 코드에 대해 생각하고 하드웨어와 더 밀접하게 상호 작용하는 방식을 강요하기 때문입니다.

오랜 경험을 바탕으로 C가 문제에 대한 더 나은 해결책을 찾도록 강요한다고 믿습니다. 부분적으로는 일부 컴파일러 작성자가 생각한 제약 조건을 충족시키기 위해 많은 시간을 낭비하지 않고 , 또는 "내부에서"무슨 일이 일어나고 있는지 파악합니다.

그런 맥락에서 C와 같은 저수준 언어는 하드웨어에 집중하고 좋은 데이터 구조 / 알고리즘 번들을 구축하는 데 많은 시간을 할애하는 반면 고수준 언어는 거기에서 무슨 일이 일어나고 있는지 궁금해하는 데 많은 시간을 할애합니다. , 그리고 특정 상황과 환경에서 완벽하게 합리적인 일을 할 수없는 이유. 컴파일러를 이길 때 (강력한 타이핑은 최악의 공격자) 시간을 생산적으로 사용하는 것은 아닙니다.

나는 아마도 프로그래머 틀에 잘 맞을 것이다. 나는 제어를 좋아한다. 제 생각에 그것은 프로그래머의 성격 결함이 아닙니다. 통제는 우리가 지불하는 것입니다. 더 구체적으로, FLAWLESSLY 제어. C는 C ++보다 훨씬 더 많은 제어를 제공합니다.


ZeroMQ의 저자 인 Martin Sistrik은 그가 왜 이제 C ++ 대신 C로 ZeroMQ를 작성하기를 원하는지에 대한 그의 토론에서 거의 같은 지적을했습니다. 확인 250bpm.com/blog:8
user2548100

3

개인적으로 4kb의 메모리를 사용하면 C ++에서 그다지 더 많은 마일리지를 얻지 못한다고 말하고 싶으므로 언어가 그다지 중요하지 않을 것이므로 작업에 가장 적합한 컴파일러 / 런타임 조합으로 보이는 것을 선택하십시오.

라이브러리도 중요하기 때문에 어쨌든 언어에 관한 모든 것이 아닙니다. 종종 C lib는 최소 크기가 약간 더 작지만 임베디드 개발을 대상으로하는 C ++ lib가 축소되었다고 생각할 수 있으므로 반드시 테스트하십시오.


2

C가 이식성에서 승리합니다. 언어 사양에서 덜 모호하기 때문입니다. 따라서 다른 컴파일러 등에서 훨씬 더 나은 이식성과 유연성을 제공합니다 (두통이 덜함).

요구 사항을 충족하기 위해 C ++ 기능을 활용하지 않으려면 C를 사용하십시오.


언어가 모호하지 않은지 여부는 상식으로 간주되던 것을 지정하는 것으로 간주하는지 여부에 따라 다르지만, 오늘날에는 그렇지 않습니다 [예 : 32 비트 자동 랩 어라운드 2의 보완 하드웨어 용 컴파일러 unsigned mul(unsigned short x, unsigned short y) { return x*y;}는없는 것으로 처리해야합니다. 제품이 2147483647을 초과하거나 void get_float_bits(float *fp, uint32_t n) { *(uint32_t)fp = n; }a float] 값을 변경하는 것으로 간주해야하는 경우에도 부작용이 발생합니다 .
supercat

2

매우 제한된 하드웨어 (4kb RAM)를 개발할 때 C89를 고수 할 이유가 있습니까?

개인적으로 임베디드 응용 프로그램에 관해서는 (내가 임베디드라고 말할 때 winCE, iPhone 등을 의미하는 것이 아닙니다. 오늘날 부풀어 오른 임베디드 장치). 자원이 제한된 장치를 의미합니다. C를 선호하지만 C ++도 꽤 많이 사용했습니다.

예를 들어, 당신이 말하는 장치는 4kb 의 RAM을 가지고 있습니다. 그래서 저는 C ++를 고려하지 않을 것입니다. 물론, C ++를 사용하여 작은 것을 디자인하고 다른 게시물에서 제안한 것처럼 응용 프로그램에서 사용을 제한 할 수 있지만 C ++는 잠재적으로 응용 프로그램을 복잡하게 만들 수 있습니다.

정적으로 링크 하시겠습니까? c ++와 c를 사용하여 정적 더미 애플리케이션을 비교할 수 있습니다. 그러면 대신 C를 고려하게 될 수 있습니다. 반면에 메모리 요구 사항 내에서 C ++ 애플리케이션을 빌드 할 수 있다면 그렇게하십시오.

IMHO, 일반적으로 임베디드 응용 프로그램에서 나는 진행되는 모든 것을 알고 싶습니다. 누가 메모리 / 시스템 리소스를 사용하고 있으며 그 양과 이유는 무엇입니까? 언제 풀어 주나요?

X 양의 리소스, CPU, 메모리 등을 사용하여 타겟을 개발할 때. 앞으로 어떤 요구 사항이 발생할지 모르기 때문에 이러한 리소스를 사용하는 데있어 더 낮은 편에 머물려고합니다. 따라서 프로젝트에 더 많은 코드를 추가해야합니다. 단순한 작은 응용 프로그램으로 "추정"되었지만 결국 훨씬 더 커졌습니다.


1
두 컴파일러를 확실히 비교할 것입니다. (btw. 운영 체제가 없기 때문에 동적으로 연결할 수 없습니다)
Piotr Czapla

2

내 선택은 일반적으로 사용하기로 결정한 C 라이브러리에 의해 결정되며 장치가 수행해야하는 작업에 따라 선택됩니다. 그래서, 9/10 배 .. 그것은 결국 uclibc 또는 newlib 및 C가됩니다. 우리가 사용하는 커널은 이것에도 큰 영향을 미칩니다. 또는 우리가 자체 커널을 작성하는 경우.

또한 공통점의 선택입니다. 대부분의 훌륭한 C 프로그래머는 C ++를 사용하는 데 아무런 문제가 없습니다 (많은 사람들이 사용하는 내내 불평하더라도) .. 그러나 나는 그 반대가 사실이라고 생각하지 않았습니다 (제 경험상).

우리가 작업중인 프로젝트 (그라운드 업 커널 포함)에서 대부분의 작업은 C로 수행되지만 작은 네트워크 스택은 C ++로 구현되었습니다. C ++를 사용하여 네트워킹을 구현하는 것이 더 쉽고 문제가 적었 기 때문입니다.

최종 결과는 장치가 작동하고 승인 테스트를 통과하거나 그렇지 않을 것입니다. z 언어를 사용하여 xx 스택 및 yy 힙 제약 조건에서 foo를 구현할 수 있다면 더 생산적으로 만드는 것을 사용하십시오.

개인적으로 선호하는 것은 C입니다.

  • 모든 코드 줄이 무엇을하고 있는지 (및 비용) 알고 있습니다.
  • 나는 모든 코드 라인이 무엇을하고 있는지 (그리고 비용) 알만큼 C ++를 잘 모른다

예, 저는 C ++에 익숙하지만 표준 C만큼 잘 모릅니다.

이제 당신이 그 반대를 말할 수 있다면, 당신이 아는 것을 사용하십시오 :) 그것이 작동한다면, 테스트를 통과하는 등 .. 문제가 무엇입니까?


2
> # 코드의 모든 줄이 무엇을하고 있는지 (그리고 비용이) 알고 있습니다. 컴파일러를 작성 했으니 확신 할 수 없습니다 ... 좋은 C 컴파일러는 다음과 같은 멋진 글로벌 개요를 가지고 있기 때문에 코드에 매우 놀라운 일을 할 수 있습니다. 소지품. 줄 단위로 컴파일하지 않습니다.
jakobengblom2

@ jakobengblom2 : 임베디드 개발의 경우 일관된 성능을 갖는 것이 최대 성능을 갖는 것보다 더 중요합니다. 코드 조각이 타이밍 요구 사항을 충족하는지 여부를 결정하려는 경우 컴파일러가 실제 펌웨어에서 작동하지 않는 "테스트"펌웨어에서 사용할 수있는 최적화를 사용하는 것은 도움이되지 않는 경향이 있습니다.
supercat

2

ROM / FLASH가 얼마나 있습니까?

4kB의 RAM은 실제 코드와 정적 데이터를 저장하기위한 수백 킬로바이트의 FLASH가 있음을 의미 할 수 있습니다. 이 크기의 RAM은 변수 용으로 만 사용되는 경향이 있으며, 이에주의하면 코드 라인 측면에서 상당히 큰 프로그램을 메모리에 맞출 수 있습니다.

그러나 C ++는 객체에 대한 런타임 구성 규칙으로 인해 코드와 데이터를 FLASH에 넣는 것을 더 어렵게 만드는 경향이 있습니다. C에서 상수 구조체는 쉽게 FLASH 메모리에 넣고 하드웨어 상수 객체로 액세스 할 수 있습니다. C ++에서 상수 객체는 컴파일러가 컴파일 타임에 생성자를 평가하도록 요구합니다. 이것은 C ++ 컴파일러가 할 수있는 것 이상이라고 생각합니다 (이론적으로는 할 수 있지만 실제로는 매우 어렵습니다). .

따라서 "작은 RAM", "대형 플래시"종류의 환경에서 C와 함께 갈 것입니다. 클래스 기반이 아닌 코드에 대한 대부분의 멋진 C ++ 기능을 가진 좋은 중간 선택 i C99에 유의하십시오.


3
C의 플래시 메모리에 넣을 동일한 구조체가 C ++의 플래시에서도 끝나지 않는 이유가 있습니까? 당신은하지 않습니다 C ++에서 구조체로 생성자를 추가 할 수 있습니다.
jalf

1

일반적으로 아니오. C ++는 C의 수퍼 세트입니다. 이것은 특히 새 프로젝트의 경우에 해당됩니다.

CPU 시간 및 메모리 공간 측면에서 비용이 많이들 수있는 C ++ 구조를 피하는 데 올바른 방향으로 가고 있습니다.

다형성과 같은 것들은 매우 가치가있을 수 있습니다-본질적으로 함수 포인터입니다. 필요한 경우 현명하게 사용하십시오.

또한 훌륭한 (잘 설계된) 예외 처리는 기존 오류 코드로 작업을 처리하는 앱보다 임베디드 앱을 더 안정적으로 만들 수 있습니다.


2
C ++는 엄밀히 말하면 C의 엄격한 상위 집합은 아니지만이 컨텍스트에서 특정 세부 사항은 특별히 중요하지 않습니다.
Arafangion

1

메모리 할당 문제의 경우 Quantum Platform과 상태 머신 접근 방식을 사용하는 것이 좋습니다. 초기화시 필요한 모든 것을 할당하기 때문입니다. 또한 경합 문제를 완화하는 데 도움이됩니다.

이 제품은 C와 C ++ 모두에서 실행됩니다.


1

어떤 사람들은 C 컴파일러가 고급 C ++ 기능을 지원할 필요가 없기 때문에 훨씬 더 효율적인 코드를 생성 할 수 있으며 따라서 최적화에 더 적극적 일 수 있다고 말합니다.

물론이 경우 두 가지 특정 컴파일러를 테스트 할 수 있습니다.


1
관련 : restrict 키워드는 C ++ (C ++ 11)에서 누락 된 유일한 최적화 관련 C 구문을 아는 한입니다.
Johan Lundberg

1

C IMHO를 선호하는 유일한 이유는 플랫폼 용 C ++ 컴파일러의 상태가 좋지 않은 경우 (버그, 최적화 불량 등)입니다.


메모리 / 리소스 활용은 어떻습니까?
Steve Lazaridis

어때요? 임베디드 시스템에서는 아무도하지 않는 RTTI를 사용하는 경우를 제외하고는 C ++ 컴파일러가 C 코드보다 덜 효율적인 코드를 생성 할 이유가 없습니다.
Nemanja Trifunovic


1

C99에 인라인이 있습니다. 당신은 배우를 좋아할 수도 있지만, dtor를 올바르게 얻는 사업은 지저분해질 수 있습니다. C를 사용하지 않는 유일한 이유가 네임 스페이스라면 저는 C89를 고수 할 것입니다. 이는 약간 다른 임베디드 플랫폼으로 이식 할 수 있기 때문입니다. 나중에 동일한 코드에서 C ++로 작성을 시작할 수 있습니다. 그러나 C ++가 C의 상위 집합이 아닌 다음을주의하십시오. C89 컴파일러가 있다고 말했지만 어쨌든 C99와의 C ++ 비교를 수행합니다. 예를 들어 첫 번째 항목은 K & R 이후 모든 C에 적용됩니다.

sizeof 'a' > 1 in C, not in C ++. C에는 VLA 가변 길이 배열이 있습니다. 예 : func (int i) {int a [i] . C에는 VAM 변수 배열 구성원이 있습니다. 예 : struct {int b; int m [];} .


1
아니요. C에서는 (sizeof 'a') == sizeof (int)가 있습니다. C ++에서는 1 == sizeof 'a'가 있습니다
hept

1
"int * a; ...; a = (int *) malloc (size * sizeof (int));"는 말할 것도 없습니다. C 및 C ++에서 작동하는 메모리를 할당하는 방법이며 둘 다 사용해서는 안됩니다. "a = malloc (size * sizeof (int));"중 하나를 사용하십시오. 또는 "vector <int> a (size);" 또는 "int * a = new int [size];" 대신.
David Thornley

1
나는 dtors에 대한 당신의 요지를 이해하지 못합니다. 그들에 대한 요점은 나머지 코드를 훨씬 복잡 하게 만든다는 것입니다 .
jalf

1
+1,이 게시물이 왜 그렇게 나쁜 랩을 받았는지 모르겠습니다. 그러나 나는 jalf에 동의하며, 소멸자 는 올바른 (RAII) 방식으로 사용될 때 코드를 강력하게 단순화 합니다. (당신은 그들이 "배후 작업"하지만, 그들이 무엇을 말할 수 있습니다 정확한 코드를 수동으로 어쨌든 일을 할 것이라고 물건을.)
j_random_hacker

1
제가 지적한 내용이 질문과 매우 관련이 있다고 생각합니다. 나는 또한 dtors가 어려울 수 있다는 내 진술을 고수하며 그 이유는 정확히 자동으로 발생하기 때문입니다. 마이너스 포인트를 얻었습니다. 내가 "YES, GO C ++ its GREAT"라고 말하지 않았기 때문인 것 같습니다.
hept

1

컴파일러에 따라 다릅니다.

모든 임베디드 컴파일러가 모든 C ++를 구현하는 것은 아니며, 그렇게하더라도 코드 부풀림을 피하는 데는 좋지 않을 수 있습니다 (항상 템플릿으로 위험 함). 몇 가지 작은 프로그램으로 테스트하고 문제가 발생하는지 확인하십시오.

하지만 좋은 컴파일러가 있다면 C ++를 사용하지 않을 이유가 없습니다.


1

"무제한"자원이있는 시스템이 없다고 말하고 싶을뿐입니다. 이 세상의 모든 것은 제한되어 있으며 모든 애플리케이션은 ASM, C, JAVA 또는 JavaScript 여부에 관계없이 리소스 사용을 고려해야합니다. "확실히"몇 Mbs를 할당하는 더미는 iPhone 7, Pixel 및 기타 장치를 매우 견고하게 만듭니다. 4kb이든 40Gb이든 상관 없습니다.

그러나 다른 측면에서 자원 낭비에 반대하는 것은 이러한 자원을 절약하는 데 걸리는 시간입니다. 이미 구현, 테스트 및 배포 된 C ++를 사용하는 대신 몇 틱과 몇 바이트를 절약하기 위해 C로 간단한 것을 작성하는 데 1 주가 더 걸립니다. 왜 귀찮게? USB 허브를 사는 것과 같습니다. 예, 직접 만들 수 있지만 더 나아질까요? 더 듬직 해요? 시간을 세면 더 저렴합니까?

측면 생각-콘센트의 전력조차 무제한이 아닙니다. 그것이 어디에서 오는지 조사하려고 노력하면 무엇인가를 태우는 것에서 주로 볼 수 있습니다. 에너지와 물질의 법칙은 여전히 ​​유효합니다. 물질이나 에너지가 나타나지 않거나 사라지는 것이 아니라 변형됩니다.


0

저는 임베디드 개발에 ISO C ++를 사용하는 방법의 예를 찾았습니다. 이것은 C ++ 또는 C를 사용할 때마다 결정을 내리는 사람에게 흥미로울 수 있습니다.

Bjarne Stroustrup 이 그의 홈페이지에서 제공했습니다. .

ISO C ++가 심각한 임베디드 시스템 프로그래밍에 어떻게 사용될 수 있는지 살펴 보려면 JSF 항공기 C ++ 코딩 표준을 참조하십시오 .


글쎄요, 날아 다니는 물건은 기가 바이트의 RAM이있는 PPC 프로세서를 사용하는 경향이 있습니다. 평균적인 리소스 제약이있는 임베디드 시스템이 아닙니다.
jakobengblom2

0

질문의 다른 측면에 대한 다른 답변 게시물 :

"malloc"

일부 이전 답변은 이에 대해 꽤 많이 이야기합니다. 왜 그 부름이 존재한다고 생각합니까? 정말 작은 플랫폼의 경우 malloc을 사용할 수 없거나 확실히 선택 사항입니다. 동적 메모리 할당을 구현하는 것은 시스템 하단에 RTOS가있을 때 의미있는 경향이 있지만 그때까지는 순전히 위험합니다.

그것 없이는 아주 멀리 갈 수 있습니다. 지역 변수에 대한 적절한 스택도 가지고 있지 않은 모든 오래된 FORTRAN 프로그램에 대해 생각해보십시오.


0

전 세계적으로 다양한 컨트롤러 제조업체가 있으며 구성에 사용해야하는 설계 및 지침 세트를 살펴보면 많은 문제가 발생할 수 있습니다. 어셈블리 언어의 주요 단점은 기계 / 아키텍처에 따라 다르다는 것입니다. 개발자가 다른 컨트롤러에 대한 코딩을 수행하기 위해 설정된 모든 지침을 마음 속으로 요청하는 것은 정말 엄청난 일입니다. 이것이 C가 하드웨어 종속적 인 세부 사항에서 알고리즘과 데이터 구조를 추상화 할 수있을만큼 충분히 높은 수준이기 때문에 C가 임베디드 개발에서 더 인기를 얻게 된 이유입니다. 소스 코드를 다양한 대상 하드웨어, 아키텍처 독립 언어에서 이식 가능하고 코드를 변환하고 유지하십시오. 그러나 우리는 C, C ++, Python, Java 등과 같은 일부 고수준 언어 (객체 지향)를 볼 수 있습니다.


0

제한 사항과 참고 사항이있는 C ++를 권장합니다.

  1. 시장 출시 시간과 유지 보수 가능성. C ++ 개발이 더 쉽고 빠릅니다. 따라서 디자인 단계에 있다면 C ++를 사용할 수있는 컨트롤러를 선택하십시오. (일부 대량 시장에서는 가능한 한 낮은 비용을 요구하므로이 선택을 할 수 없습니다.)

  2. 속도. C는 C ++보다 빠를 수 있지만 속도 향상이 크지 않은지 확인하십시오. 따라서 C ++로 갈 수 있습니다. 알고리즘을 개발하고 테스트하고 필요한 경우에만 더 빠르게 만듭니다 (!). 프로파일 러를 사용하여 병목 지점을 지적하고이를 외부 "C" 방식으로 다시 작성하여 C 속도를 달성하십시오. (여전히 ASM에서 해당 부분을 구현하는 것이 느리다면)

  3. 이진 크기. C ++ 코드는 더 크지 만 여기 에 세부 사항을 알려주는 훌륭한 답변 이 있습니다. 주어진 C 코드의 컴파일 된 바이너리의 크기는 C 또는 C ++ 컴파일러를 사용하여 컴파일되었는지에 관계없이 동일합니다."실행 파일 크기는 언어와 거의 관련이 없지만 프로젝트에 포함 된 라이브러리와 관련이 있습니다." ++ C로 이동하지만, 고급 기능을 피하기 같은 streams, string, new, virtual기능 등을 검토 모든 라이브러리 기능 때문에 크기 제한, 최종 코드를시키기 전에 (에 따라 대답)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.