在 WinCC 腳本或 C 動作中,常需解析逗號分隔的 CSV 格式字串,例如 "地址,名稱,單位,類型"。標準庫 strtok 是首選工具,但其非執行緒安全、會修改原字串、需小心處理連續分隔符等特性必須充分理解。
NULL 以繼續分割。\0,返回 Token 起始位址。#include
#include
// 假設輸入格式:Address,Name,Unit,Type
// 輸出參數:Add, Name, Unit(需呼叫端預先分配足夠緩衝區)
void ParseAddressAndUnit(char *str, char *Add, char *Name, char *Unit) {
if (!str || !Add || !Name || !Unit) return;
char *token = strtok(str, ","); // 第一次分割
if (token) {
strncpy(Add, token, strlen(token));
Add[strlen(token)] = '\0'; // 確保結尾
}
int field = 0;
while ((token = strtok(NULL, ",")) != NULL) {
field++;
if (field == 1) { // 第二欄:Name
strncpy(Name, token, strlen(token));
Name[strlen(token)] = '\0';
} else if (field == 3) { // 第四欄:Unit
strncpy(Unit, token, strlen(token));
Unit[strlen(token)] = '\0';
break; // 取得目標欄位,提前結束
}
}
}
| 問題 | 後果 | 解決方案 |
|---|---|---|
| 修改原字串 | 若原字串為常值或需保留,會導致崩潰或資料遺失 | 先 strcpy 到可寫緩衝區再分割 |
| 非執行緒安全 | 多執行緒同時呼叫會互相干擾 | 使用 strtok_r (POSIX) 或 strtok_s (C11 Annex K) |
| 連續分隔符合併 | "a,,b" 只能取到 "a" 和 "b",中間空欄位丟失 | 若需保留空欄位,改用 strsep 或手寫解析器 |
| 緩衝區溢位 | strncpy 不自動加 \0 當長度剛好等於來源 | 手動加 dest[n-1] = '\0' 或改用 snprintf |
// POSIX 標準,需 _POSIX_C_SOURCE >= 1
void ParseThreadSafe(char *str, char *Add, char *Name, char *Unit) {
char *saveptr = NULL;
char *token = strtok_r(str, ",", &saveptr);
// 後續呼叫傳入 NULL 與同一 saveptr
while ((token = strtok_r(NULL, ",", &saveptr)) != NULL) {
// ...
}
}
strtok 通常安全,但若在同時觸發的多個動作中使用,仍有風險。strtok 輕量便利,適合簡單 CSV 解析。掌握其修改原字串、靜態狀態、連續分隔符合併三大特性,並配合 strtok_r/strtok_s 處理並發場景,即可在 WinCC 專案中穩健應用。複雜格式(含引號、跳脫字元)建議引入成熟 CSV 解析庫或手寫狀態機。