---
code: c_sdk_installation
name: "C"
wikiToken: SLlQwuOYRifeDVkRAxTc08pVnMg
parentWikiToken: O3YxwgHGiiEnvYkHCcIcX51inkf
updateTime: 1745310920000
sourceUrl: https://docs-v2.thinkingdata.cn/?version=v5.0&lan=zh-CN&code=c_sdk_installation
---
# C

::: tip 提示

 在接入前, 请先阅读接入前准备。

 :::

**最新版本为**：v2.0.0

**更新时间为**：2023-11-30

**资源下载**：源代码

::: warning 注意

当前文档适用于 v2.0.0 及以后的版本，历史版本请参考 C SDK 接入指南（V1）

::: 

### 一、集成SDK

1. 下载 C SDK 源码，修改 `CMakeLists.txt` 文件，使用`logconsumer`方式编译出 .a 文件
```
cmake_minimum_required(VERSION 3.12)
project(thinking_data_c)
message(STATUS "[ThinkingData] CMAKE_HOST_SYSTEM: ${CMAKE_HOST_SYSTEM} ")

include_directories(include)

#################################################################

# Product Library: logging consumer
if(WIN32)
    add_compile_definitions(USE_WIN)
    set(CMAKE_C_FLAGS "-std=c89 -pedantic-errors -m64")
else()
    add_compile_definitions(USE_POSIX)
    set(CMAKE_C_FLAGS "-std=c89")
endif()
SET(TE_LIB_NAME thinkingdata)
add_library(${TE_LIB_NAME} src/thinkingdata.c src/td_json.c src/td_list.c src/td_util.c src/td_logger_consumer.c)
if(WIN32)
    include_directories(thirdparty/pcre/include)
    link_directories(thirdparty/pcre/lib)
    target_link_libraries(${TE_LIB_NAME} pcre_x64)
endif()
```

编译项目，获取`libthinkingdata.a`文件。

1. 安装Logbus
我们推荐使用SDK+LogBus的形式，完成服务端数据的采集上报.您可以参考以下文档完成Logbus的安装:LogBus使用指南

### 二、初始化

以下是SDK初始化的示例代码:

```
struct TDAnalytics* ta = NULL;
struct TDConsumer* consumer = NULL;

TDConfig* config = td_init_config();
char* logPath = "LOG_DIRECTORY";
TD_ASSERT(*TD_OK *== td_add_string("file_path", logPath, strlen(logPath), config));

if (*TD_OK *!= td_init_consumer(&consumer, config)) {
    fprintf(stderr, "Failed to initialize the consumer.");
}
td_free_properties(config);

if (*TD_OK *!= td_init(consumer, &ta)) {
    fprintf(stderr, "Failed to initialize the SDK.");
    return 1;
}
```

`LOG_DIRECTORY`为写入本地的文件夹地址。您只需将 LogBus 的监听文件夹路径设置为此处的地址，即可使用 LogBus 进行数据的监听上传。

### 三、常用功能

为了保证访客 ID 与账号 ID 能够顺利进行绑定，如果您的游戏中会用到访客 ID 与账号 ID，我们极力建议您同时上传这两个 ID，否则将会出现账号无法匹配的情况，导致用户重复计算，具体的 ID 绑定规则可参考用户识别规则一章。

#### 3.1 发送事件

您可以调用 `td_track` 来上传事件，建议您根据先前梳理的文档来设置事件的属性以及发送信息的条件，以下是发送事件的示例代码:

```
// 生成自定义属性
TDProperties *properties = td_init_properties();
// 设置用户的ip地址，AE 系统会根据IP地址解析用户的地理位置信息
TD_ASSERT(*TD_OK *== td_add_string("#ip", "192.168.1.1", strlen("192.168.1.1"), properties));
// 添加自定义属性
TD_ASSERT(*TD_OK *== td_add_string("channel", "ta", strlen("ta"), properties));//字符串
TD_ASSERT(*TD_OK *== td_add_int("age", 1, properties)); //数字
TD_ASSERT(*TD_OK *== td_add_bool("is_success", *TD_TRUE*, properties));//布尔
TD_ASSERT(*TD_OK *== td_add_date("birthday", time(NULL), 0, properties));//时间
// 数组
TD_ASSERT(*TD_OK *== td_append_array("arr", "value", strlen("value"), properties));
TD_ASSERT(*TD_OK *== td_append_array("arr", "value1", strlen("value1"), properties));
// 对象
TDProperties *object = td_init_custom_properties("object");
TD_ASSERT(*TD_OK *== td_add_string("key", "value", strlen("value"), object));
TD_ASSERT(*TD_OK *== td_add_property(object, properties));
// 对象组
TDProperties *object1 = td_init_custom_properties("object1");
TD_ASSERT(*TD_OK *== td_add_string("key", "value", strlen("value"), object1));
TD_ASSERT(*TD_OK *== td_append_properties("object_arr", object1, properties));
// 上报带有自定义属性的事件数据，同样account_id 和 distinct_id 必须至少设置其中一个
TD_ASSERT(*TD_OK *== td_track("account_id", "distinct_id", "payment", properties, ta));
td_free_properties(properties);
```

- 事件的名称是字符串类型，只能以字母开头，可包含数字，字母和下划线 "_"，长度最大为 50 个字符。
- Key 为该属性的名称，为字符串类型，规定只能以字母开头，包含数字，字母和下划线 "_"，长度最大为 50 个字符，对字母大小写不敏感，AE 会统一转化为小写字母
- Value 为该属性的值，支持字符串、数字、布尔、时间、对象、对象组、数组
<!-- unsupported block: 34 -->

**用户属性的要求与事件属性保持一致**

#### 3.2 设置用户属性

对于一般的用户属性，您可以调用 `td_user_set` 来进行设置，使用该接口上传的属性将会覆盖原有的属性值，如果之前不存在该用户属性，则会新建该用户属性，类型与传入属性的类型一致，此处以设置用户名为例：

```
// 此时username为TA
// account_id 和 distinct_id 必须至少设置其中一个
TDProperties *user_properties = td_init_properties();
TD_ASSERT(*TD_OK *== td_add_string("user_name", "TA", strlen("TA"), user_properties));
TD_ASSERT(*TD_OK *== td_user_set(account_id, distinct_id, user_properties,ta));
td_free_properties(user_properties);

// 此时userName为TE
TDProperties *user_properties2 = td_init_properties();
TD_ASSERT(*TD_OK *== td_add_string("user_name", "TE", strlen("TE"), user_properties2));
TD_ASSERT(*TD_OK *== td_user_set(account_id, distinct_id, user_properties2,ta));
td_free_properties(user_properties2);
```

#### 3.3 数据上报

使用 `td_init_consumer()` 方式初始化 SDK，SDK 会实时的将采集到的数据写入磁盘。

`td_flush()` 函数内部是将文件系统中默认的内存缓存实时同步到磁盘。一般不需要手动调用。

```
td_flush(ta);
```

#### 3.4 关闭SDK

```
td_free(ta);
td_consumer_free(consumer);
```

<!-- unsupported block: 34 -->

关闭并退出 SDK，请在关闭服务器前调用本接口，以避免缓存内的数据丢失

### 四、最佳实践

```
struct TDAnalytics* ta = NULL;
struct TDConsumer* consumer = NULL;

TDConfig* config = td_init_config();
char* logPath = "LOG_DIRECTORY";
TD_ASSERT(*TD_OK *== td_add_string("file_path", logPath, strlen(logPath), config));

if (*TD_OK *!= td_init_consumer(&consumer, config)) {
    fprintf(stderr, "Failed to initialize the consumer.");
}
td_free_properties(config);

if (*TD_OK *!= td_init(consumer, &ta)) {
    fprintf(stderr, "Failed to initialize the SDK.");
    return 1;
}

// 生成自定义属性
TDProperties *properties = td_init_properties();
// 设置用户的ip地址，AE 系统会根据IP地址解析用户的地理位置信息
TD_ASSERT(*TD_OK *== td_add_string("#ip", "192.168.1.1", strlen("192.168.1.1"), properties));
// 添加自定义属性
TD_ASSERT(*TD_OK *== td_add_string("channel", "ta", strlen("ta"), properties));//字符串
TD_ASSERT(*TD_OK *== td_add_int("age", 1, properties)); //数字
TD_ASSERT(*TD_OK *== td_add_bool("is_success", *TD_TRUE*, properties));//布尔
TD_ASSERT(*TD_OK *== td_add_date("birthday", time(NULL), 0, properties));//时间
// 数组
TD_ASSERT(*TD_OK *== td_append_array("arr", "value", strlen("value"), properties));
TD_ASSERT(*TD_OK *== td_append_array("arr", "value1", strlen("value1"), properties));
// 对象
TDProperties *object = td_init_custom_properties("object");
TD_ASSERT(*TD_OK *== td_add_string("key", "value", strlen("value"), object));
TD_ASSERT(*TD_OK *== td_add_property(object, properties));
// 对象组
TDProperties *object1 = td_init_custom_properties("object1");
TD_ASSERT(*TD_OK *== td_add_string("key", "value", strlen("value"), object1));
TD_ASSERT(*TD_OK *== td_append_properties("object_arr", object1, properties));
// 上报带有自定义属性的事件数据，同样account_id 和 distinct_id 必须至少设置其中一个
TD_ASSERT(*TD_OK *== td_track("account_id", "distinct_id", "payment", properties, ta));
td_free_properties(properties);

// 此时username为TA
// account_id 和 distinct_id 必须至少设置其中一个
TDProperties *user_properties = td_init_properties();
TD_ASSERT(*TD_OK *== td_add_string("user_name", "TA", strlen("TA"), user_properties));
TD_ASSERT(*TD_OK *== td_user_set("account_id", "distinct_id", user_properties,ta));
td_free_properties(user_properties);

// 此时userName为TE
TDProperties *user_properties2 = td_init_properties();
TD_ASSERT(*TD_OK *== td_add_string("user_name", "TE", strlen("TE"), user_properties2));
TD_ASSERT(*TD_OK *== td_user_set("account_id", "distinct_id", user_properties2,ta));
td_free_properties(user_properties2);
```
