마이크로 컨트롤러를위한 효율적인 C 코드 작성에 대한 자료? [닫은]


15

여기에 심각한 도움이 필요했습니다. 나는 프로그래밍을 좋아합니다. 최근에 C 언어에 대한 많은 책 (예 : K & R)과 기사 / 포럼을 읽었습니다. 심지어 리눅스 코드를 보려고 시도했지만 (시작해야 할 곳이 없어졌지만 작은 라이브러리로 엿보는 것이 도움이 되었습니까?)

나는 자바 프로그래머로 시작했고 자바에서는 꽤 잘 자랐다. 프로그램이 너무 커지면 클래스로 분할 한 다음 함수로 추가하십시오. 지침은 코드를 읽을 수있게 유지하고 주석을 추가합니다. 정보 숨기기 및 OOP 기술을 사용하십시오. 일부는 여전히 C에 적용됩니다.

나는 지금 C로 코딩 해 왔으며 지금까지 프로그램이 어떤 식 으로든 작동하도록합니다. 많은 사람들이 성능 / 효율성, 알고리즘 / 디자인, 최적화 및 유지 관리성에 대해 이야기합니다. 어떤 사람들은 다른 사람보다 스트레스를 더 많이 받지만 전문가가 아닌 소프트웨어 엔지니어에게는 다음과 같은 소리가 자주 들립니다. Linux 커널 개발자는 코드를 가져 가지 않습니다.

내 질문은 이것입니다 : 나는 자원을 낭비하지 않고 8 비트 마이크로 컨트롤러 용 코드를 작성할 계획입니다 . 내가 자바 배경에서 왔기 때문에 더 이상 똑같지 않다는 것을 알고 있습니다. 이제 성능과 크기가 중요합니다. 8 비트 마이크로 컨트롤러를위한 효율적인 (모범 사례 내) C 코드에 대한 리소스 / 트릭?

또한, inline assembly마이크로 컨트롤러 표준에 충실하면서도 중요한 역할을합니다. 그러나 모든 사람에게 적용되는 효율성에 대한 일반적인 경험 규칙이 있습니까?

예를 들어 : 언제든지 register unsigned int variable_name;선호 char됩니다. 또는 uint8_t 큰 숫자가 필요하지 않은 경우 사용 하십시오.

편집 : 모든 답변과 제안에 감사드립니다. 지식을 공유하려는 모든 사람의 노력에 감사드립니다.


2
x86 프로세서에서는 그렇지 않지만 마이크로 컨트롤러에서는 경우에 따라 성능 저하를 막으려면 어셈블리를 대신 사용하는 것이 좋습니다.
Rei Miyasaka

3
@Rei : 수제 조립은 메모리를 적게 사용하고 최신 C 컴파일러보다 빠릅니다. C에서 수행해야 할 때 어셈블리 코드를 작성하는 것은 시간 낭비입니다.
mattnz

1
@mattnz 현대적으로, 당신은 얼마나 새로운 이야기를합니까? 솔직히 말해서 저는 거의 10 년 동안 마이크로 컨트롤러 용 코드를 작성하지 않았습니다.
Rey Miyasaka

2
한 가지 간단한 팁 : 미크론 제어에서는 "더 간단하면 빠르다"는 것이 일반적입니다. 복잡한 칩 (ARM 이상)에서는 하드웨어가 너무 많은 최적화를 수행하므로 테스트 할 때까지 알 수 없습니다.
Javier

1
@ReiMiyasaka의 유지 보수 비용이 대폭 증가했습니다. 우수한 C 컴파일러는 숙련 된 프로그래머와 거의 동일한 코드를 생성 할 수 있습니다.

답변:


33

저는 20 년 이상의 임베디드 시스템을 보유하고 있으며 대부분 8 및 16 마이크로입니다. 질문에 대한 짧은 대답은 다른 소프트웨어 개발과 동일합니다. 필요할 때까지 최적화하지 말고 최적화해야 할 것을 알 때까지 최적화하지 마십시오. 신뢰할 수 있고, 읽고, 유지 보수가 가능한 코드를 먼저 작성하십시오. 조기 최적화는 임베디드 시스템에서 큰 문제가 될 수 있습니다.

"자원 낭비없이"프로그램 할 때 시간을 자원으로 생각하십니까? 그렇지 않다면, 누가 당신을 위해 시간을 지불하고, 아무도 없다면, 당신은 그것과 더 나은 것을 가지고 있습니까? 임베디드 시스템 설계자가 선택해야 할 사항은 하드웨어 비용과 엔지니어링 시간 비용입니다. 100 개 유닛을 배송 할 경우 10 만개 단위의 더 큰 마이크로를 사용하는 경우, 단위당 1.00 달러 절약은 소프트웨어 개발 1 년 (시장 출시 시간, 기회 비용 등 무시)과 100 만 단위와 동일합니다. 리소스 사용에 대한 강박 관념으로 ROI를 얻지 만, 임베디드 프로젝트가 1 백만 개 (생산 비용이 낮고 초기 투자 비용이 높음)를 판매하도록 설계되어 1 백만 대를 달성 한 적이 없었기 때문에 조심해야합니다.

즉, (소형) 임베디드 시스템으로 고려해야 할 사항은 느리게 진행될뿐만 아니라 예기치 않은 방식으로 작동을 중지하기 때문입니다.

a) 스택-일반적으로 스택 크기가 작고 종종 스택 프레임 크기가 제한됩니다. 스택 활용도가 항상 무엇인지 알고 있어야합니다. 스택 문제로 인해 가장 교묘 한 결함이 발생할 수 있습니다.

b) 힙-다시 작은 힙 크기이므로 불필요한 메모리 할당에주의하십시오. 조각화가 문제가됩니다. 이 두 가지를 사용하면 부족할 때 수행 할 작업을 알아야합니다. OS가 제공 한 페이징으로 인해 대규모 시스템에서는 발생하지 않습니다. 즉, malloc이 NULL을 반환하면이를 확인하고 무엇을합니까? 모든 맬로는 검사 및 처리기, 코드 팽창이 필요합니까? 가이드로-대안이 있으면 사용하지 마십시오. 대부분의 소형 시스템은 이러한 이유로 동적 메모리를 사용하지 않습니다.

c) 하드웨어 인터럽트-안전하고시기 적절하게 처리하는 방법을 알아야합니다. 안전한 재진입 코드 작성 방법도 알아야합니다. 예를 들어, C 표준 라이브러리는 일반적으로 재진입 할 ​​수 없으므로 인터럽트 핸들러 내부에서 사용해서는 안됩니다.

d) 조립-거의 항상 조기 최적화. C가 할 수없는 것을 달성하기 위해서는 기껏해야 소량 (인라인)이 필요합니다. 연습으로 손으로 만들어진 작은 조립법을 처음부터 작성하십시오. C에서 동일한 작업을 수행하십시오. 성능을 측정하십시오. 나는 C가 더 빠를 것이라고 내기보다 더 읽기 쉽고 유지 보수가 쉽고 확장 가능하다는 것을 알고있다. 이제 연습의 2 부-어셈블리와 C에 유용한 프로그램을 작성하십시오.
또 다른 연습으로서, 리눅스 커널에 대한 리눅스 커널에 대해 아래 단락을 읽어보십시오.

그것을하는 방법을 아는 것은 가치가 있으며, 하나 또는 두 개의 공통 마이크로 언어의 언어에 능숙 할 수도 있습니다.

e) "unsigned int variable_name 등록", "register"는 70 년대 초 (40 년 전)의 명령이 아닌 컴파일러에 대한 힌트이며 항상 그랬습니다. 2012 년에는 컴파일러가 똑똑하고 마이크로 명령어가 너무 복잡해 키 스트로크가 낭비되었습니다.

당신의 리눅스 의견으로 돌아가서-여기서 당신이 가진 문제는 우리가 단지 1 백만 단위를 말하지 않고, 우리는 평생 동안 100, 수백만을 말하고 있다는 것입니다. 인간적으로 가능한 최적의 엔지니어링 시간과 비용은 가치가 있습니다. 최고의 엔지니어링 실무의 좋은 예이지만, 대부분의 임베디드 시스템 개발자는 리눅스 커널이 요구하는 것만 큼 현명한 사람 일 것입니다.


4
mattnz : 이것은 .stackexchange 사이트에서 가장 사랑스러운 답변 중 하나입니다.
Ahmed Masud

1
이 답변을 개선 할 수 없습니다. 난 단지 어셈블리 코드를 삽입하는 것은 거의 성능에 대한 의미가 없다는 것을 추가 할 수 있지만, C로 할 쉽지 않을 수도 I / O 칩 또는 다른 하드웨어 트릭을 파고 같은 것들에 대한 감각을 만들 수
마이크 Dunlavey

@mattnz 잘 대답 해 주셔서 감사합니다. +1
AceofSpades

1
정확한 타이밍을 위해서는 @MikeDunlavey 어셈블러가 필요한 경우가 있습니다. 비트 뱅킹을 사용하여 I / O 핀에서 NTSC 비디오를 생성하는 비디오 오버레이를 방금 완료했습니다. 타이밍은 3 클럭 사이클 동안 전압이 높고 6시 간 동안 낮습니다. ...
Martin Beckett

@Martin : 완벽하게 이해됩니다. 그 수준에서 코딩한지 오래되었습니다.
Mike Dunlavey가

3

귀하의 질문 ( "자원 낭비 없음")이 너무 일반적이므로 많은 조언을하기가 어렵습니다. 말 그대로, 자원을 낭비하고 싶지 않다면 한 걸음 물러서서 무언가를 해야하는지 여부, 즉 다른 방법으로 문제를 해결할 수 있는지 평가해야합니다.

또한 유용한 조언은 제약 조건에 따라 크게 달라집니다. 어떤 종류의 시스템을 구축하고 있으며 어떤 종류의 CPU를 사용하고 있습니까? 어려운 실시간 시스템입니까? 코드와 데이터를 위해 얼마나 많은 메모리가 있습니까? 기본적으로 모든 C 연산 (특히 곱셈과 나눗셈)과 어떤 유형을 지원합니까? 보다 일반적으로 : 전체 데이터 시트를 읽고 이해 하십시오.

가장 중요한 조언 : 간단하게 유지하십시오.

예 : 복잡한 데이터 구조 (해시, 트리, 가능하면 연결된 목록)를 잊고 고정 크기 배열을 사용하십시오. 배열이 너무 느리다는 측정을 통해 입증 한 후에 만 ​​더 복잡한 데이터 구조를 사용해야합니다.

또한 과도하게 설계하지 마십시오 (Java / C # 개발자가 수행하려는 경향이 있음). 너무 많은 계층화없이 간단한 절차 코드를 작성하십시오. 추상화에는 비용이 있습니다!

전역 변수를 사용하는 아이디어에 익숙해지고 [예외가없는 경우 정리에 매우 유용];)

인터럽트를 처리해야하는 경우 재진입에 대해 읽으십시오. 재진입 코드를 작성하는 것은 쉽지 않습니다.


3

나는 mattnz의 대답에 동의합니다 . 30 년 전에 8085에서 프로그래밍을 시작한 다음 Z80을 8080으로 빠르게 마이그레이션했습니다. 그 후 68300 시리즈 마이크로 컨트롤러, 80x86, XScale, MXL 및 8 비트 PICS로갔습니다. 추측은 내가 완전한 원을 의미합니다. 기록을 위해, 나는 몇몇 주요 마이크로 프로세서 제조업체의 FAE가 목적에 맞는 코드 재사용을 위해 객체 지향 방식이지만 여전히 어셈블러를 사용한다고 말할 수 있습니다.

승인 된 답변에 표시되지 않는 것은 대상 프로세서 유형 및 / 또는 제안 된 아키텍처에 대한 설명입니다. 제한된 메모리를 가진 0.50 $ 8 비터입니까? 파이프 라이닝과 8Meg 플래시를 갖춘 ARM9 코어입니까? 메모리 관리 코 프로세서? OS가 있습니까? while (1) 루프? 초기 생산 가동률이 10 만대 인 소비자 기기? 큰 아이디어와 꿈을 가진 스타트 업 회사?

현대 컴파일러가 훌륭한 최적화 작업을 수행한다는 데 동의하지만, 30 년 동안 디버거를 멈추지 않고 생성 된 어셈블리 코드를보고 프로젝트에서 어떤 일이 일어 났는지 볼 수있는 프로젝트를 한 적이 없습니다 ( 파이프 라이닝과 최적화가 시작될 때 악몽이 될 것이므로 조립 지식이 중요합니다.

그리고 저는 엔지니어링 부사장, 쿼트 컨테이너에 갤런을 넣거나 하드웨어 문제를 해결하기 위해 소프트웨어 솔루션을 사용하여 0.05 달러를 절약하도록 강요하지 않은 고객 인 CEO를 갖지 못했습니다. 너무 어려워?). 메모리 (코드 또는 데이터) 최적화는 항상 계산됩니다.

내 요점은 순수한 프로그래밍 관점에서 프로젝트를 보면 더 좁은 범위의 솔루션을 현명하게 얻을 수 있다는 것입니다. Mattnz는 제대로 작동합니다. 작동하고 더 빠르고 작게 작동하지만 코딩에 대해 생각하기 전에 요구 사항과 결과물에 많은 시간을 소비해야합니다.


안녕하세요 Gio, 게시물에 불필요한 HTML을 피하고 Markdown 구문을 대신 사용하십시오 . 들어 <br />그냥 눌러 입력 할 수 있고, 단락만을위한 그들 사이에 빈 줄을 둡니다. 또한 다른 답변을 참조 할 때 이에 대한 링크를 추가하십시오. 이 시점에서 몇 가지 답변 만있을 수 있지만 더 많은 페이지가 분산되어있을 수 있으며 어떤 답변을 의미하는지는 명확하지 않습니다. 수정 내역 을 확인하여 편집 내용을 확인하십시오.
yannis

@Gio 다른 중요한 요소를 언급 해 주셔서 감사합니다. +1 :)
AceofSpades

+1-내 대답의 멋진 확장.
mattnz

1

Manttz의 대답은 "하드웨어에 근접한"프로그래밍을 수행하는 방법에 대한 가장 중요한 요점을 제시합니다. 이것은 결국 C의 의미입니다.

그러나 "Class"라는 엄격한 키워드는 C에 존재하지 않지만 하드웨어에 가까이 있더라도 C의 객체 지향 프로그래밍 측면 에서 생각 하는 것은 매우 간단 합니다.

이 답변을 고려할 수 있습니다 .이 점을 설명하는 C 프로그램에 대한 OO 모범 사례 .

다음은 C로 객체 지향 코드를 작성하는 데 도움이되는 리소스입니다.

ㅏ. C에서의 객체 지향 프로그래밍
b. 사람들이 아이디어를 교환 할 수있는 좋은 장소
c. 그리고 여기에 전체 책이 있습니다

내가 제안하고 싶은 또 다른 좋은 자료는 다음과 같습니다.

위대한 코드 시리즈 작성 . 이 책은 두 권입니다. 첫 번째 책은 낮은 수준의 작업에서 기계의 매우 중요한 측면을 다룹니다. 두 번째로 다룬 책은 "Thinking low level-writing high level"입니다.


1

몇 가지 문제가 있습니다. 먼저이 프로젝트 / 코드를 이식 가능하게 하시겠습니까? 이식성으로 인해 성능과 크기가 증가하고, 선택한 플랫폼과 작업이 초과 크기를 줄이고 성능을 저하시킬 수 있습니까?

예, 부호없는 정수 또는 반바지 대신 부호없는 문자를 반환하는 8 비트 컴퓨터에서는 성능과 크기를 향상시키는 한 가지 방법이 있습니다. 마찬가지로 16 비트 시스템에서는 부호없는 반바지와 32 비트 기계 부호없는 정수를 사용하십시오. 예를 들어 시스템 전체에서 이식성을 위해 어디에서나 부호없는 정수를 사용하면 (예를 들어 ARM이 가장 낮은 전력, 가장 작은 장치 시장으로 내려가는 등) 해당 코드가 엄청나다는 것을 알 수 있습니다. 8 비트 마이크로. 물론 int 또는 short 또는 char없이 unsigned를 사용하고 컴파일러가 최적의 크기를 선택하도록 할 수 있습니다.

인라인 어셈블리뿐만 아니라 일반적으로 어셈블리 언어입니다. 인라인 어셈블리는 이식성이 뛰어나고 asm 함수를 호출하는 것보다 쓰기가 어렵습니다. 그렇습니다. 통화 설정 및 반납은 쉽지만 개발, 유지 관리 및 제어가 쉬워집니다. 규칙은 여전히 ​​적용되며, 실제로 필요한 경우에만 asm으로 작성하십시오. 컴파일러 출력이이 영역의 문제이며 수동으로 수행하여 얻을 수있는 성능 향상 정도를 결론 내기 위해 작업을 수행 한 적이 있습니까? 그런 다음 C와 asm을 혼합하기 시작하자마자 이식성과 유지 보수로 돌아갑니다. C와 asm을 혼합 할 때마다 이식성이 손상 될 수 있으며 다른 사람과 작업중인 사람에 따라 프로젝트를 유지 관리하기 어려울 수 있습니다. 현재 개발중인 제품이며 다른 사람이 계속 관리해야합니다. 해당 분석을 완료하면 인라인으로 이동해야하는지 또는 똑바로 조립해야하는지 자동으로 알 수 있습니다. 나는 현장에서 25 년 이상의 경력을 가지고 있으며 매일 C와 asm 혼합물을 작성하고 하드웨어 / 소프트웨어 계층에 거주하며 인라인 asm을 사용하지 않습니다. 컴파일러에 특정적인 노력을 기울일 가치가 거의 없으며 가능한 경우 (거의 모든 곳에서) 컴파일러 비특이적 코드를 작성합니다.

모든 질문의 핵심은 C 코드를 분해하는 것입니다. 컴파일러가 코드를 사용하여 수행하는 작업을 배우고, 원하는 경우 시간이 지남에 따라 컴파일러를 조작하여 원하는 코드를 만들지 않고 원하는 코드를 생성하는 방법을 배울 수 있습니다. 시간이 지남에 따라 컴파일러를 조작하여 여러 대상에서 효율적인 코드를 생성하여 asm에 의존하지 않고도 코드를 더 이식성있게 만들 수 있습니다. 부호없는 문자가 8 비트 마이크로에서 부호없는 것보다 함수에서 상태 리턴으로 더 나은 이유를 보는 데 아무런 문제가 없을 것입니다. 마찬가지로 부호없는 문자는 16 및 32 비트 시스템에서 더 많은 비용이 듭니다 (일부 아키텍처는 밖으로, 일부는하지 않습니다).

일부 8 비트 마이크로 컨트롤러는 모두 컴파일러에 친숙하지 않으며 컴파일러에서 우수한 코드를 생성하지 않습니다. 이러한 장치가 해당 대상에 적합한 컴파일러를 작성하기 위해 컴파일러 시장을 만들 필요가 충분하지 않으므로 거기에있는 컴파일러는 더 많은 비즈니스, 비 asm 프로그래머를 유치해야합니다. 컴파일러가 손으로 작성한 asm보다 낫기 때문이 아닙니다. . 이 세계로 진입하는 팔과 밉은 많은 작업을 수행 한 컴파일러, 꽤 좋은 코드를 생성하는 컴파일러 등을 가지고있는 대상을 가지면서 해당 모델을 변경하고 있습니다. 물론 프로세서가있는 마이크로는 여전히 asm으로 드롭 해야하는 경우가 많지만 자주는 아니지만 컴파일러에게 사용하지 않는 것보다 원하는 것을 알려주는 것이 훨씬 쉽습니다. 컴파일러를 조작하는 것은 추악하고 읽을 수없는 코드가 아닙니다. 실제로 이것은 반대의 깔끔하고 간단한 코드이며 아마도 몇 가지 항목을 다시 정렬했을 것입니다. 함수의 크기와 매개 변수 수를 제어하면 컴파일러 출력에 큰 차이가 있습니다. 컴파일러 또는 언어의 기발한 기능을 피하십시오 .KISS, 간단하게 바보로 유지하고 종종 훨씬 더 좋고 빠른 코드를 생성합니다.


당신은 당신이 생산하는 제품의 유형을 언급하지 않습니다, 나는 그것이 매우 큰 수량, 낮은 마진 또는 미친 틈새가있는 특정 틈새 시장이라고 가정합니다. 작은 8 비트 마이크로 및 수공 어셈블러 또는 더 큰 마이크로 및 C를 사용해야하는 경우 비즈니스 수준에서 결정하는 것이 중요합니다. (삭제 된) 의견에 대한 반향으로 8 비트 마이크로와 함께 작업합니다. 필요한 마이크로보다 큰 것으로 시작하고 BOM 비용이 문제가되는 경우에만 수정) 시장 출시 시간, 운영 비용 및 상각 된 개발 비용으로 인해 BOM에 10 또는 20 센트를 추가 할 수 있습니다.
mattnz
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.