【发布时间】:2016-09-27 20:41:55
【问题描述】:
(作为序言,我的 C 很糟糕)
我正在尝试将字符串从 iOS 发送到 BLE 设备。我用swift对字符串进行编码并这样写:
func sendUserName(userName: String) {
let bytes: [UInt8] = Array(userName.utf8)
print(bytes.count)
let data = NSData(bytes: bytes, length: bytes.count)
capsenseLedBoard!.writeValue(data, forCharacteristic: userIdCharacteristic, type: CBCharacteristicWriteType.WithResponse)
}
我发送这个字符串"THISISATEST123456789",这行print(bytes.count) 打印出20。
我像这样在 BLE 设备上接收数据并将其传递给下面的 userDidConnect 函数:
userDidConnect((char *)wrReqParam->handleValPair.value.val);
我有一个名为Event 的struct,看起来像这样:
struct Event {
char time[20]; // The time in ISO 1601 format
char name[3]; // The two character name of the event. See header for declarations.
char userId[20]; // The userId of the connected user if one is present.
struct Event* next;
};
我有一个这样声明的全局变量:
char currentlyConnectedUserID[20];
然后我有一个如下所示的入队函数:
/**
Creates a new Event and adds to the linked list.
@param time The time in ISO 8601 format.
@param name The name descriptor of the event ("VS", "VO", etc.)
@param userId The id of the user who is currently connect (if they are connected).
*/
void enqueueEvent(char time[20], char name[3], char userId[20]) {
struct Event* temp = (struct Event*)malloc(sizeof(struct Event));
strncpy( temp->time, time, 20);
strncpy( temp->name, name, 3);
strncpy( temp->userId, userId, 20);
temp->next = NULL;
if(front == NULL && rear == NULL) {
front = rear = temp;
return;
}
rear->next = temp;
rear = temp;
}
我有一个函数,它接受一个新的 userId,然后创建一个新的 Event 并将其添加到链表中。这就是它应该做的:
void userDidConnect(char *userId)
{
size_t destination_size = sizeof(userId);
snprintf(currentlyConnectedUserID, destination_size, "%s", userId);
//enqueueEvent("2007-03-01T13:00:20", "UC", currentlyConnectedUserID);
showMessageInUART(currentlyConnectedUserID, sizeof(currentlyConnectedUserID));
}
目前,如果我运行上面的userDidConnect 方法,我可以正确打印出currentlyConnectedUserID。但是,如果我取消注释掉这一行:
//enqueueEvent("2007-03-01T13:00:20", "UC", currentlyConnectedUserID);
我遇到“崩溃”。我在一个相当晦涩的 IDE(赛普拉斯的 PSoC Creator)中执行此操作,因此我看不到任何错误日志或 IDE 崩溃日志。我能说的唯一方法是永远不会调用showMessageInUART,所以我知道它必须是那条线。
如果我这样做,我可以成功创建一个新事件并将其加入队列:
enqueueEvent("2007-03-01T13:00:20", "UC", "1234567891234567891");
我唯一的想法是数组的大小可能是错误的?也许?或者也许有一些尾随的\0 把事情搞砸了?
建议更新:
我试过这样做:
size_t destination_size = strlen(userId) + 1;
这为currentlyConnectedUserID 提供了正确的值,但是排队仍然会导致崩溃。
--
我已将strcpy 替换为strncpy,这仍然会导致崩溃;(
--
试过这个以确保我没有溢出但仍然没有工作:
sprintf(currentlyConnectedUserID, "%.19s", userId);
更新
由于没有断点,我将队列更新为如下所示:
void enqueueEvent(char time[20], char name[3], char userId[20]) {
UART_UartPutString("start enqueue");
struct Event* temp = (struct Event*)malloc(sizeof(struct Event));
UART_UartPutString("1");
strncpy( temp->time, time, 20);
UART_UartPutString("2");
strncpy( temp->name, name, 3);
UART_UartPutString("3");
strncpy( temp->userId, userId, 20);
UART_UartPutString("4");
temp->next = NULL;
UART_UartPutString("5");
if(front == NULL && rear == NULL) {
front = rear = temp;
return;
}
rear->next = temp;
rear = temp;
}
这条线崩溃了:
strncpy( temp->time, time, 20);
我们从来没有在这里成功过:UART_UartPutString("2");
如果我从 main 调用相同的函数,它工作正常。知道为什么从不同的方法调用它会在这里崩溃吗?
【问题讨论】:
-
我怀疑
userDidConnect没有做你想做的事。userId是一个指针,所以sizeof(userId)将在 32 位机器上返回 4,在 64 位机器上返回 8。如果userId指向一个字符串,我敢打赌你想要的是字符串长度。 -
@yano 我试过用
strlen替换sizeof仍然可以正确转换为currentlyConnectedUserID但是排队仍然崩溃:( -
然后
sizeof(userId) + 1将根据您的架构返回 5 或 9。我的猜测是你有字符串问题,但这里没有足够的代码可以确定。你要向userDidConnect传递什么? -
任何时候你在 C 中覆盖一个缓冲区,你都会执行 未定义的行为,这意味着在那之后所有的赌注都被取消了。你可能会很幸运,事情会奏效,它可能会在看似随机的地方崩溃。仅仅因为事情在
enqueueEvent中崩溃并不一定意味着这就是错误所在。这可能只是暴露了之前的错误。 -
根据您传递给
enqueueEvent的内容,我认为没有问题。您正在传递长度为 19、2、19 的字符串,这些字符串将适合 20、3、20(包括空字节)的缓冲区。这就是为什么我认为真正的问题在此之前的某个地方。此外,在enqueueEvent中,确保malloc没有返回NULL。如果是这样,那也会导致崩溃。也不知道front或rear是什么。这里根本没有足够的代码来知道问题是什么,因此我的所有猜测。
标签: c arrays swift struct bluetooth-lowenergy