6.3 C++11에서 C99 인터페이스 연동
개요
C++11 프로젝트는 extern "C" 를 통해 C99 SDK 헤더와 import 라이브러리를 직접 호출할 수 있습니다. 이 방식의 핵심 가치는 인터페이스를 평면적으로 유지하고 의존성을 최소화하면서 ArmHandle* 기반의 C 스타일 수명 주기를 계속 사용하는 것입니다.
적용 시나리오
| 시나리오 | 설명 |
|---|---|
| 최소 의존성 | C99 공개 헤더와 C/C++ 표준 라이브러리에만 의존 |
| 레거시 프로젝트 | 프로젝트가 아직 C++11에 머물러 있어 C++17로 전환하기 어려움 |
| 플랫폼 호환성 | 평면 ABI와 수동 수명 주기 관리가 필요 |
헤더 포함
cpp
extern "C" { // C++11 프로젝트에서 C linkage 방식으로 C99 SDK 헤더를 포함합니다.
#include "c_arm_api.h" // C99 SDK 최상위 헤더를 포함합니다.
} // C linkage 선언을 종료합니다.최소 연동 예제
예제 코드
cpp
#include <stdio.h>
extern "C" {
#include "c_arm_api.h"
}
int main(void)
{
// [ZH] 本示例直接在源码中写死连接地址,不解析命令行参数。
// [EN] This example hard-codes the connection addresses in the source code and does not parse command-line arguments.
ArmHandle* handle = Arm_Create();
if (handle == NULL) {
printf("[cpp11_c99_connect_get_version] 创建句柄失败 / Failed to create the handle\n");
return 1;
}
// [ZH] 连接机器人。
// [EN] Connect to the robot.
const int connectRet = Arm_Connect(handle, "10.27.1.2", "10.27.1.102");
if (connectRet != 0) {
printf("[cpp11_c99_connect_get_version] 连接失败 / Connect failed, 状态码 / Status code: %d\n", connectRet);
Arm_Destroy(handle);
return 1;
}
printf("[cpp11_c99_connect_get_version] 机器人连接成功 / Robot connected successfully\n");
// [ZH] 读取控制器版本。
// [EN] Read the controller version.
char version[128] = {0};
const int versionRet = Arm_Info_GetControllerVersion(
handle,
version,
sizeof(version)
);
if (versionRet != 0) {
printf("[cpp11_c99_connect_get_version] 获取版本失败 / Get version failed, 状态码 / Status code: %d\n", versionRet);
Arm_Disconnect(handle);
Arm_Destroy(handle);
return 1;
}
printf("[cpp11_c99_connect_get_version] 控制器版本 / Controller version: %s\n", version);
// [ZH] 断开连接并销毁句柄。
// [EN] Disconnect and destroy the handle.
Arm_Disconnect(handle);
Arm_Destroy(handle);
printf("[cpp11_c99_connect_get_version] 示例结束 / Example finished\n");
return 0;
}CMake 구성
대응하는 전체 CMake 파일:
txt
cmake_minimum_required(VERSION 3.20)
project(c99_connect_get_version LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
add_executable(c99_connect_get_version
src/main.cpp
)
set_target_properties(c99_connect_get_version PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/output")
target_include_directories(c99_connect_get_version PRIVATE src dependency/include)
target_compile_options(c99_connect_get_version PRIVATE /utf-8)
target_link_libraries(c99_connect_get_version PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/dependency/lib/AgilebotCppSdk.lib")빌드 및 실행
powershell
powershell -ExecutionPolicy Bypass -File example/cpp11/c99_connect_get_version/build/build.ps1대응하는 빌드 스크립트:
ps1
param()
chcp 65001 > $null
[Console]::OutputEncoding = [Text.Encoding]::UTF8
# 在示例脚本目录下执行,统一使用相对路径访问工程和产物。
Set-Location $PSScriptRoot
# 清理上一次拷贝的 SDK 依赖与示例运行产物,避免旧 DLL 干扰当前验证。
Remove-Item -Recurse -Force ..\dependency -ErrorAction Ignore
Remove-Item -Recurse -Force ..\output -ErrorAction Ignore
powershell -ExecutionPolicy Bypass -File ..\..\..\build\prepare_dependency.ps1 -Package c99
# 配置并编译当前独立示例工程。
cmake -S .. -B ..\buildcache -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_LINKER_TYPE=LLD
if (Test-Path ..\buildcache\compile_commands.json) {
Copy-Item -Force ..\buildcache\compile_commands.json ..\compile_commands.json
}
cmake --build ..\buildcache
powershell -ExecutionPolicy Bypass -File ..\..\..\build\run_example.ps1 -Executable ..\output\c99_connect_get_version.exe설명:
- 빌드 스크립트는
output/release/c99-sdk/에서 의존성을 자동으로 준비합니다. - 실행 전에 장치를 변경해야 하는 경우 예제의 컨트롤러 주소와 티치 펜던트 주소를 수정합니다.
스레드 모델
C++11에서 C99 인터페이스로 SDK를 사용할 때 스레드 모델은 C99와 완전히 동일합니다.
- 동기 호출은 호출 스레드에서 실행됩니다.
- 주기 작업은
Arm_Info_AcquireAccess()및Arm_Jogging_ContinuousMove()처럼 세션 전용 네트워크 스레드에서 실행됩니다. - 구독 콜백은 WebSocket 메시지가 도착할 때 트리거됩니다.
자세한 내용은 1.3 스레드 모델을 참고하십시오.
C++17 SDK와 비교
| 특성 | C++11 + C99 | C++17 SDK |
|---|---|---|
| 진입 형태 | extern "C" + ArmHandle* | Arm 객체 |
| 반환 방식 | 상태 코드 + out 파라미터 | STATUS_CODE / std::pair |
| 리소스 관리 | 수동 Destroy | RAII 자동 해제 |
| 컨테이너 반환 | 호출자가 배열을 직접 관리 | std::vector / std::string |
| 적용 범위 | 레거시 프로젝트, 최소 의존성 통합 | 신규 프로젝트, 객체형 래퍼 |
예제 목록
example/cpp11 디렉터리는 example/c99 와 정렬된 예제 코드를 제공합니다.
| 예제 | 설명 |
|---|---|
arm_connect_disconnect | Core create/connect/disconnect/destroy |
info_basic | 모든 Arm Info 인터페이스 |
alarm_query | 모든 Arm Alarm 인터페이스 |
motion_basic | 모든 Arm Motion 인터페이스 |
program_execution | Arm Program、BasScript、ArmProgramPose |
registers_basic | 모든 Arm Registers 인터페이스 |
signals_basic | 모든 Arm Signals 인터페이스 |
trajectory_basic | Arm Trajectory 및 Arm RealTimeTrajectory |
file_manager_basic | 모든 Arm FileManager 인터페이스 |
coordinate_system_basic | 모든 Arm CoordinateSystem 인터페이스 |
modbus_basic | 모든 Arm Modbus 인터페이스 |
jogging_basic | 모든 Arm Jogging 인터페이스 |
extension_basic | 모든 Arm Extension 인터페이스 |
sub_pub_basic | 모든 Arm SubPub 인터페이스 |
c99_connect_get_version | 최소 연동 폐루프 예제 |
주의 사항
- 헤더 파일은 반드시
extern "C"안에 넣어야 합니다. ArmHandle*는Arm_Destroy()로 수동 해제해야 합니다.- 모든 인터페이스의 반환값을 확인해야 합니다.
- 같은
ArmHandle*를 여러 스레드에서 동시에 무분별하게 사용하지 마십시오.