본문 바로가기
회사/CAPL

섹션 4_CANoe - CAPL과 Panel 기본 (섹션 4)

by 응가1414 2024. 10. 19.

## CAPL 변수, 데이터 타입, 상수, #define

 

 

  • 지역변수:
    변수가 선언된 종괄호 내부에서만 접근할 수 있는 변수입니다.
  • 예제 코드 설명:
    예시 코드에서 ONKEY A 이벤트ONKEY B 이벤트 두 개의 서로 다른 이벤트가 있습니다.
    이 두 이벤트 모두에서 접근할 수 있는 변수는 전역변수입니다.
  • 전역변수와 지역변수의 차이:
    전역변수는 코드 전체에서 접근할 수 있는 반면, 지역변수는 각각의 종괄호 내에서만 접근 가능합니다.
  • 전역변수의 위치:
    CAPL에서는 전역변수 선언 위치가 중요합니다. 전역변수는 특정한 코드 영역에 선언되어야 합니다.
  • CANoe 환경에서의 전역변수 선언:
    CANoe 같은 환경에서는 별도의 코드 영역 없이 코드의 빈 공간에서 변수를 선언할 수 있습니다.
    이러한 변수들은 variables 영역에 선언된 것으로 취급됩니다.
  • 전역변수 선언의 필수성:
    전역변수는 반드시 variables 영역 안에 선언해야 하며, 그렇지 않을 경우 에러가 발생합니다.

 

 

 

int var_1;

var_1 = 0;

 

선언을 먼저 해야한다.

  • 지역 변수 위치 규칙
    • 지역 변수도 선언하는 위치가 정해져 있습니다.
    • 이 규칙은 옛날 버전의 C 언어 규칙과 유사하며, 현재는 C에서는 사용되지 않지만 CAPL에서는 여전히 적용됩니다.
  • 변수 선언 순서
    • 함수나 이벤트 코드 작성 시 변수를 최상단에 먼저 선언해야 합니다.
    • 예를 들어 test function()이라는 함수 안에서 1, 2, 3이라는 세 개의 변수를 사용한다고 할 때,
      변수를 두 개 이상 선언한 후 다른 연산을 작성하면 CAPL은 이를 에러로 인식합니다.
  • 변수 선언 규칙의 핵심
    • 새로운 변수 선언은 항상 코드의 맨 앞에 위치해야 합니다.
    • 중간에 연산이 들어가고 난 후에 변수를 선언하면 에러가 발생합니다.
  • for문 안의 변수 선언
    • CAPL에서는 for문 안에 변수를 선언할 수 있지만, 다른 언어와 달리 for문 안에서 직접 변수를 선언하면 에러가 발생할 수 있습니다.
    • 이는 CAPL의 컴파일러가 변수를 선언하는 위치를 엄격히 관리하기 때문입니다.
  • 변수 선언 유의사항
    • 변수 선언은 항상 함수나 코드 블록의 가장 상단에 위치해야 하며, 다른 코드와 혼용하지 않아야 합니다.
    • 잘못된 위치에 변수를 선언할 경우 코드 컴파일이 되지 않거나 에러가 발생합니다.

 

 

CAPL에서 변수 초기화 관련 규칙 정리

  1. 초기화되지 않은 변수의 기본값
    • 지역 변수전역 변수 모두 초기 값을 명시적으로 지정하지 않으면 기본값으로 0이 할당됩니다.
  2. 컴파일러마다 다른 동작
    • C 언어의 경우, 컴파일러에 따라 초기화되지 않은 변수쓰레기 값이 들어갈 수 있습니다.
    • 그러나 CAPL에서는 초기화 값을 따로 지정하지 않으면 무조건 0으로 초기화됩니다.
  3. 초기화 습관의 중요성
    • 명시적으로 초기화하지 않더라도 CAPL은 자동으로 0으로 설정하지만, 예측 가능한 코드 작성을 위해 초기화를 습관화하는 것이 좋습니다.
    • 이는 코드의 가독성과 유지보수성을 높이는 데 도움이 됩니다.

 

CAPL에서 변수의 지역성과 초기화 규칙 정리

  1. CAPL에서 지역 변수와 전역 변수의 차이
    • 지역 변수는 함수나 이벤트 안에서 호출될 때마다 0으로 초기화됩니다.
    • 전역 변수는 프로그램이 시작될 때 한 번만 초기화되고 이후 값이 계속 유지됩니다.
  2. C 언어의 static 변수와 유사한 동작
    • CAPL의 모든 지역 변수는 static 변수처럼 초기화됩니다. 즉, 매번 함수가 호출될 때마다 초기값으로 설정되지 않고, 프로그램 실행 동안 유지됩니다.
  3. 지역 변수와 전역 변수의 이름 충돌
    • 전역 변수와 지역 변수의 이름이 같을 경우, 지역 변수가 우선적으로 적용됩니다.
    • 서로 다른 함수나 이벤트 안에서도 동일한 이름의 지역 변수를 각각 사용할 수 있습니다, 이는 서로 독립된 변수로 동작합니다.
  4. 변수 선언 예제
    • 예를 들어 testA 함수와 testB 함수에 동일한 이름의 변수를 선언하더라도, 두 변수는 서로 독립적으로 동작합니다.
    • 전역 변수와 동일한 이름의 지역 변수가 있을 경우, 해당 함수나 이벤트에서는 지역 변수가 사용됩니다.
  5. CAPL의 for문과 변수 사용
    • CAPL에서 for문 내부에서 변수를 선언하면 지역 변수처럼 동작하지만, 명시적으로 초기화되지 않으면 자동으로 0으로 초기화됩니다.
  6. 변수 사용 시 주의할 점
    • CAPL에서의 변수 사용은 항상 명확한 범위와 초기화 규칙을 염두에 두어야 합니다.
    • 특히 전역 변수와 지역 변수의 이름이 중복될 경우 우선순위에 주의해야 합니다.
      • 예: 함수 안에서 전역 변수와 동일한 이름의 지역 변수를 선언하면, 해당 함수에서는 지역 변수가 사용됩니다.
  7. 실행 결과 예시
    • 예를 들어, testA 함수에서 전역 변수와 동일한 이름의 지역 변수를 사용하고 A 키를 눌렀을 때 출력이 다르게 나타납니다. 지역 변수의 값이 200으로 설정된 경우, 해당 값이 우선 출력됩니다.

 

CAPL에서 지원되는 데이터 타입에 대한 정리

  1. CAPL의 정수형 타입
    • 일반적인 C 언어에서는 int 타입이 4바이트 크기지만, CAPL에서는 2바이트입니다.
    • 4바이트 정수를 사용하려면 **int32 또는 rom**을 사용해야 합니다.
    • 8바이트 정수형 변수를 선언하려면 **int64_t**와 같은 타입을 사용합니다.
  2. 부호 없는 정수형 (Unsigned)
    • CAPL에서는 unsigned 키워드가 따로 지원되지 않습니다.
      대신, 부호 없는 데이터 타입을 명시적으로 사용해야 합니다.
      예를 들어, unsigned int 대신 **uint16**와 같은 타입을 사용합니다.
  3. 실수형 데이터 타입
    • C 언어와 동일하게 **float와 double**을 사용할 수 있습니다.
    • 그러나 CAPL에서 float는 4바이트, double은 8바이트로 C 언어와 동일합니다.
  4. 배열 및 고수준 데이터 타입 지원
    • CAPL에서는 배열형 변수와 **고수준 데이터 타입(예: 문자열, 이넘)**도 사용할 수 있습니다.
  5. 포인터 타입의 부재
    • CAPL은 C 언어와 다르게 포인터 타입을 지원하지 않습니다.
      이는 메모리 접근과 관련된 기능이 제한됨을 의미합니다.
  6. CAPL의 주요 데이터 타입 정리
    • 2바이트 정수: 기본 int 타입은 2바이트.
    • 4바이트 정수: int32를 사용해야 함.
    • 8바이트 정수: int64_t 사용.
    • 부호 없는 정수: uint16, uint32 등 사용.
    • 실수: float와 double 사용 가능.
  7. 핵심 요약
    • int의 기본 크기가 2바이트인 점에 주의.
    • unsigned 키워드 사용 불가 – 대신 명시적인 데이터 타입 사용.
    • 포인터 타입 미지원으로 인해 메모리 관련 기능 제한.

struct 선언 및 사용 예제 (구조체)

capl
코드 복사
struct TestStruct { int data1; // 정수형 변수 float data2; // 실수형 변수 int arr[4]; // 정수 배열 (4개 원소) };
  • struct는 여러 개의 변수를 하나의 그룹으로 묶는 데 사용됩니다. 여기서는 정수형 변수, 실수형 변수, 그리고 정수 배열로 구성된 구조체 TestStruct를 정의했습니다.
capl
코드 복사
variables { struct TestStruct var1 = {123, 40.123, {1, 2, 3, 4}}; // 초기화된 선언 struct TestStruct var2; // 초기화되지 않은 선언 }
  • var1은 선언과 동시에 {123, 40.123, {1, 2, 3, 4}} 값으로 초기화되었습니다.
  • var2는 선언만 하고 값을 할당하지 않은 상태입니다.

2. enum 선언 및 사용 예제 (열거형)

capl
코드 복사
enum EcuName { Steering, BMS, Brake, Engine };
  • EcuName 열거형은 ECU 이름들을 정의합니다. 각 상수는 0부터 자동으로 순서대로 값이 할당됩니다.
    예: Steering = 0, BMS = 1, Brake = 2, Engine = 3
capl
코드 복사
enum IgnState { Ign_Off = -1, Ign_On = 3 };
  • IgnState 열거형은 시동 상태를 나타내며, 직접 값을 지정했습니다.
    예: Ign_Off = -1, Ign_On = 3
capl
코드 복사
variables { enum EcuName test_var1; // EcuName 타입 변수 선언 enum IgnState test_var2; // IgnState 타입 변수 선언 }
  • test_var1과 test_var2는 각각 EcuName과 IgnState 타입의 변수를 선언한 것입니다.

CAPL에서의 struct와 enum의 유용성

  • struct: 복잡한 데이터 구조를 그룹화해 다룰 때 유용합니다. 예를 들어, ECU 데이터메시지 데이터를 묶어 관리할 수 있습니다.
  • enum: 상태나 옵션을 정수 값으로 표현하여 코드의 가독성과 유지 보수를 높입니다. 시동 상태(IgnState)나 모듈 이름(EcuName) 같은 고정된 값들에 주로 사용됩니다.

CAPL의 특성

  • CAPL은 이벤트 기반 프로그래밍이므로, 각 메시지나 타이머 이벤트에 따라 구조체 변수나 열거형 변수를 사용할 수 있습니다.
  • 예를 들어 CAN 메시지를 수신할 때 메시지의 데이터 부분을 구조체로 파싱하거나, ECU 상태를 열거형을 통해 관리할 수 있습니다.

1. 사용 불가능한 예시

capl
코드 복사
#define VERSION 7 on message BMS { int test = VERSION; write("version is %d", test); }
  • 이 코드가 작동하지 않는 이유:
    • CAPL에서는 #define으로 정의된 매크로를 변수처럼 직접 대입하는 방식이 지원되지 않습니다.
    • VERSION을 변수처럼 사용하고자 했으나, CAPL은 매크로를 이처럼 데이터 대입 목적으로 사용하지 못합니다.
    • CAPL의 매크로는 주로 조건부 컴파일 제어에 사용됩니다.

2. 사용 가능한 예시

capl
코드 복사
variables
{
    #define DEBUG 1
}

void test_function(void)
{
    #if DEBUG
    write("test sentence1");
    #endif

    #if DEBUG
    write("test sentence2");
    #endif
}
  • 이 코드가 올바른 이유:
    • 조건부 컴파일을 통해 DEBUG 값이 1일 때만 특정 코드가 실행되도록 작성되었습니다.
    • #if와 #endif 구문으로 매크로를 활용해 코드 블록을 제어합니다.
    • DEBUG가 1이면 write 함수들이 실행되고, 0이면 해당 블록들이 무시됩니다.

 

1. CAPL에서의 #define 매크로와 디버깅

  • #define 매크로의 활용:
    • #define을 사용하여 특정 코드를 활성화 또는 비활성화할 수 있습니다.
    • 이 매크로는 디버깅 코드처럼 일시적으로 사용해야 하는 코드의 활성화/비활성화에 유용합니다.
      예를 들어:
      capl
      코드 복사
      #define DEBUG 1 // 디버깅 활성화 #if DEBUG write("디버깅 코드 실행 중"); #endif
    • DEBUG 값에 따라 코드의 실행 여부가 결정됩니다. 나중에 이 코드를 비활성화하고 싶다면, #define DEBUG 0으로 변경하면 됩니다.

2. 비활성화와 주석 처리의 문제점

  • 주석 처리 대신 매크로 사용:
    • 많은 디버깅 코드를 주석 처리하면 코드가 복잡해지고 유지보수가 어려워질 수 있습니다.
    • 매크로를 사용하면 코드 삭제 없이 조건부로 실행을 제어할 수 있어 효율적입니다.
    • 코드가 많을 때 주석으로 관리하는 것보다 매크로로 관리하는 것이 편리합니다.

3. 디버깅 코드의 비활성화와 활성화

  • 개발 중에는 디버깅을 통해 코드가 올바르게 작동하는지 확인해야 합니다. 그러나 개발이 완료된 후에는 디버깅 코드를 비활성화해야 코드가 깔끔해집니다.
  • 매번 주석을 추가하고 제거하는 대신, #define 매크로를 통해 필요한 부분만 유동적으로 디버깅할 수 있습니다.

4. 매크로 사용 위치 및 전형적인 사용법

  • #define 매크로는 코드의 최상단 또는 변수 선언 이후에 위치해야 합니다.
  • 전형적인 사용법으로, 초기 코드의 조건에 따라 특정 부분의 코드만 실행하거나 무시할 수 있습니다.