gpt4 book ai didi

c - 在 C 中连接字符串的最谨慎的方法

转载 作者:太空宇宙 更新时间:2023-11-04 00:47:56 25 4
gpt4 key购买 nike

我的固件在每 10 秒一个周期内将字符串移动到输出(SD 卡上的 csv 文件)。问题是字符串有时会以不确定的方式改变添加不应该存在的值或在中间放置空间。这与 sprintf 函数或该字符串的动态分配内存有关吗?

void archPolling()
{

double archCountVal[200];
float archDataVal[100];
char *FilStringMeas = malloc(sizeof(char) * 2048);
char *FilArchive = malloc(sizeof(char) * 4096);
vArchEvent eventArch = STATE_POLLING;
unsigned char CiphCRC[5];
FIL FilData;
UINT bw;
int queueSize = 0;

if ( xSemaphoreTake( MutexMeasurment, 200 ) == pdTRUE)
{
eventArch = STATE_COLLECT;
}

if (eventArch == STATE_COLLECT)
{

while (uxQueueMessagesWaiting(xDataQueue) > 0)
{
xQueueReceive(xDataQueue, &archDataVal[queueSize], 0);
queueSize++;
}
xSemaphoreGive(MutexMeasurment);

if (queueSize > 0 && timerFlag == 1)
eventArch = STATE_FORM;
else
eventArch = STATE_POLLING;
}

if (eventArch == STATE_FORM)
{
//portENTER_CRITICAL();
HAL_RTC_GetTime(&RtcHandle, &RTCTimeArch, FORMAT_BIN);
HAL_RTC_GetDate(&RtcHandle, &RTCDateArch, FORMAT_BIN);
sprintf(FilArchive, "%02d-%02d-%02d,%02d:%02d:%02d,1", RTCDateArch.Date, RTCDateArch.Month, RTCDateArch.Year, RTCTimeArch.Hours, RTCTimeArch.Minutes, RTCTimeArch.Seconds);
sprintf(FilStringMeas, ",");
for (int i = 0; i < queueSize; i++)
{
sprintf(FilStringMeas, "%s%f,", FilStringMeas, archDataVal[i]);
}

strcat(FilArchive, FilStringMeas);
archCRC((BYTE *) FilArchive, strlen(FilArchive), CiphCRC);
strcat(FilArchive, (char *) CiphCRC);
strcat(FilArchive, "\n");
//portEXIT_CRITICAL();
eventArch = STATE_SYNC;
}

if (eventArch == STATE_SYNC)
{
f_open(&FilData, "0:55AD001.csv", FA_OPEN_EXISTING | FA_WRITE);
f_lseek(&FilData, f_size(&FilData));
f_write(&FilData, FilArchive, strlen(FilArchive) * sizeof(char), &bw);
f_close(&FilData);
timerFlag = 0;
eventArch = STATE_POLLING;
}

free(FilStringMeas);
free(FilArchive);
}

编辑:错误输出示例

0,0,1,3.512586,42.960911,,46.487427,24.501009,1.512586,27.498940,40.960911,36.598400,11.039062,9.401555,25.498940,42.487427,20.501009,7.512586,17.401556,36.960911,32.598400,7.039061,5.512586,31.498940,48.487427,16.501009,5.039061,13.401555,29.498940,46.487427,24.501009,1.512586,27.498940,44.487427,36.598400,11.039062,9.401555,38.960911,42.487427,20.501009,7.512586,33.498940,36.960911,32.598400,7.039061,15.401555,31.498940,48.487427,16.501009,3.512586,13.401555,42.960911,38.598400,3.039061,1.512586,27.498940,44.487427,22.501009,11.09062,AAAA

0,0,1,34.471630,6.303817,15,15.528328,45.382984,32.471630,6.617044,4.303817,29.472881,47.696175,16.527170,4.617044,11.528328,41.382984,38.471630,24.527170,0.303817,25.472881,43.696175,36.471630,10.617044,17.528328,37.382984,41.696175,20.527170,8.617044,15.528328,45.382984,32.471630,6.617044,13.528328,29.472881,47.696175,16.527170,2.303817,11.528328,41.382984,38.471630,12.617044,0.303817,25.472881,43.696175,22.527170,10.617044,17.528328,37.382984,34.471630,20.527170,6.303817,31.472881,39.696175,32.471630,6.617044,13.528328,43.382984,496175,AAAA

最佳答案

我认为 Jack Whitman 指出的问题是造成虚假输出的原因:您不应将要打印的字符串作为参数传递给 sprintf。另一个潜在风险是缓冲区溢出,sprintfstrcat 无法防范。 (好吧,无法防范,因为他们不知道缓冲区有多大。)

您构建一个字符串,然后将其附加到一个文件中。您的问题的一种解决方案是不创建中间字符串,而是将部分格式化的字符串直接附加到文件中。

另一种解决方案是跟踪写入的字符数。此信息由 printf 的所有变体返回,除非发生错误,该错误由 -1 发出信号。然后附加到字符串或多或少像:

size_t n = 0;

n += sprintf(str + n, ...);
n += sprintf(str + n, ...);

如果您使用 snprintf 而不是 sprintf,您还可以防止缓冲区溢出。

这有点麻烦。 s*printf 函数的问题在于它们总是从头开始填充字符串并在后续调用同一输出缓冲区时覆盖数据,这有点不直观,因为 fprintf appnds 到文件并且不会覆盖之前写入同一输出文件的任何内容。

如果您有更多情况需要通过连续调用格式化打印例程来构建字符串,您可以编写一个小型框架。下面的示例从固定大小的 char 缓冲区创建一个“appender”并连续填充它。结果可能会被截断以防止溢出,但总是会产生一个以 null 结尾的字符串,除非 rem 为 0:

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h> // needed for va_list

struct appender {
char *str; // original buffer
size_t rem; // remaining space
size_t n; // (potential) characters written
};

int appprintf(struct appender *app, const char *fmt, ...)
{
va_list args;
char *p = app->rem ? app->str + app->n : NULL;
int n;

va_start(args, fmt);
n = vsnprintf(p, app->rem, fmt, args);
app->rem = (n < app->rem) ? app->rem - n : 0;
app->n += n;
va_end(args);

return n;
}

int main()
{
char buffer[64];
struct appender app = { buffer, sizeof(buffer) };
int i;

for (i = 0; i < 100; i++) {
appprintf(&app, " %d", i);
}

puts(buffer);

return 0;
}

关于c - 在 C 中连接字符串的最谨慎的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29966116/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com