我在嵌入式平台上使用C很有经验,但我在操作系统中很少使用C。我目前正在制作树莓派2。
我在C语言中工作,我需要制作一个实用程序,从二进制文件的一部分创建CSV文件。二进制文件包含许多小时的数据,并格式化为一系列"块",每个块包含约2000毫秒的数据。该程序将遍历每个块并提取数据,直到到达结束时间。
当我尝试相对较小的二进制到csv转换时,该程序可以工作,但没有理由不适用于我可以识别的较大转换。当我在MAX_TIME_SAMPLE_TO_CONVERT为180000的情况下运行程序时,在正常运行和valgrind中都没有问题。当我将"MAX_TIME_SAMPLE_TO_CONVERT"更改为200000时,即出现分段错误。这只需要60kB内存的malloc,这应该是轻而易举的事。当我从命令行运行"free"时,我有超过500MB的可用空间。
当我运行valgrind时,我得到了一个有点神秘的输出,但它告诉我有问题的行号(我正在使用-g选项构建),这些行号正是使用malloc:的变量
/* save the samples into the arrays
* that will become the CSV files */
int32_t time = 0;
for(int j = 0; (j < numOfSamples) && (time < endTime); j++){
time = networkTime + (j * SAMPLE_INTERVAL_MS);
timeArray[sampleIndex] = time;
sampleArray[sampleIndex] = uncompressedBlockDataArray[j];
sampleIndex++;
}
完整代码:
int32_t startTime = getStartTime(argc, argv);
int32_t endTime = getEndTime(argc, argv);
/* calculate the amount of memory required to construct each array,
* limiting the maximum amount in order to conserve memory */
uint32_t timeWindow = endTime - startTime;
if(verbose)
printf("time window: %dmsn", timeWindow);
if(timeWindow > MAX_SAMPLE_TIME_TO_CONVERT){
timeWindow = MAX_SAMPLE_TIME_TO_CONVERT;
endTime = startTime + MAX_SAMPLE_TIME_TO_CONVERT;
if(verbose){
printf("warning: specified time window results in too many samplesn");
printf("ttime window truncated to %dmsn", timeWindow);
printf("tnew end time: %dn", endTime);
}
}
uint32_t numOfSamples = timeWindow/SAMPLE_INTERVAL_MS;
if(verbose)
printf("each CSV file will contain up to %d samples (maximum of %dms)n", numOfSamples, MAX_SAMPLE_TIME_TO_CONVERT);
/* allocate memory to temporarily store the
* data from the binary file as it is read */
int32_t *timeArray = (int32_t *)malloc(sizeof(uint32_t) * numOfSamples);
uint16_t *sampleArray= (uint16_t *)malloc(sizeof(uint16_t) * numOfSamples);
if(verbose)
printf("Allocating %d bytes for time and %d for samplesn", sizeof(uint32_t) * numOfSamples, sizeof(uint16_t) * numOfSamples);
if((timeArray == NULL) || (sampleArray == NULL)){
printf("Not enough RAM, exiting...n");
return -1;
}
/* iterate through the SN array, saving each binary section to a CSV file */
for(int i = 0; serialNumbersToExport[i] > 0; i++){
uint32_t sampleIndex = 0;
if(verbose)
printf("nAttempting binary-to-csv export of serial number %d...n", serialNumbersToExport[i]);
/* create the source file paths */
char strSrcPath[DEFAULT_STR_LENGTH];
snprintf(strSrcPath, DEFAULT_STR_LENGTH, "/home/updsys/data/SN%d.ubin", serialNumbersToExport[i]);
if(verbose)
printf("tAttempting to access '%s'...n", strSrcPath);
/* open the source file */
FILE *sourceF;
sourceF = fopen(strSrcPath, "rb");
if(sourceF != NULL){
if(verbose)
printf("tSource binary found, proceeding...n");
/* find the starting point in the file, begin writing to the file
* until you reach the end of the file or the end time specified */
int32_t networkTime = 0;
uint32_t fileByteOffset = 0;
uint8_t blockHeaderArray[COMPRESSION_BLOCK_HEADER_LENGTH];
uint8_t blockDataArray[MAX_BLOCK_SIZE_IN_BYTES];
/* while time is less than end time OR we have reached the end of the file */
while(networkTime < endTime){
if(verbose)
printf("tbinary file offset: %dn", fileByteOffset);
fseek(sourceF, fileByteOffset, SEEK_SET); // set read pointer to beginning of file
/* when fread returns 0, break the loop */
if(fread(blockHeaderArray, 1, COMPRESSION_BLOCK_HEADER_LENGTH, sourceF) == 0)
break;
fileByteOffset += COMPRESSION_BLOCK_HEADER_LENGTH;
fseek(sourceF, fileByteOffset, SEEK_SET);
networkTime = (uint32_t)blockHeaderArray[0]
+ (((uint32_t)blockHeaderArray[1]) << 8)
+ (((uint32_t)blockHeaderArray[2]) << 16)
+ (((uint32_t)blockHeaderArray[3]) << 24);
uint16_t numOfSamples = blockHeaderArray[4];
uint16_t compressedWidth = blockHeaderArray[6];
uint16_t numBytesToRead = getBlockNumOfBytes16(compressedWidth, numOfSamples);
fread(blockDataArray, 1, numBytesToRead, sourceF);
fileByteOffset += numBytesToRead;
/* if the start time is less/equal to than the time at
* the end of the current block, then decompress and
* save the data */
int32_t timeAtEndOfBlock = networkTime + (int32_t)(numOfSamples * SAMPLE_INTERVAL_MS);
if(startTime <= timeAtEndOfBlock){
if(verbose)
printf("tstart time (%d) within block end time (%d), decompressing...n", startTime, timeAtEndOfBlock);
/* use to save single-block data to */
uint16_t uncompressedBlockDataArray[(MAX_BLOCK_SIZE_IN_BYTES/2)] = {0};
/* prepare to decompress */
CompressionDataStruct16 compressionDataStruct;
compressionDataStruct.sampleCount = numOfSamples;
compressionDataStruct.compressedWidth = compressedWidth;
compressionDataStruct.compressedData = blockDataArray;
compressionDataStruct.uncompressedData = uncompressedBlockDataArray;
decompressTo16(&compressionDataStruct);
/* save the samples into the arrays
* that will become the CSV files */
int32_t time = 0;
for(int j = 0; (j < numOfSamples) && (time < endTime); j++){
time = networkTime + (j * SAMPLE_INTERVAL_MS);
timeArray[sampleIndex] = time;
sampleArray[sampleIndex] = uncompressedBlockDataArray[j];
sampleIndex++;
}
}
}
if(verbose){
printf("t%d samples found, closing source binary file...n", sampleIndex);
}
fclose(sourceF);
/* if data was found, then write to CSV; otherwise move on */
if(sampleIndex > 0){
/* save the variables to '~/data/nodeNum.csv' */
char strDestPath[DEFAULT_STR_LENGTH];
snprintf(strDestPath, DEFAULT_STR_LENGTH, "/home/updsys/data/SN%d.csv", serialNumbersToExport[i]);
FILE *f;
f = fopen(strDestPath, "w"); // overwrite
for(uint16_t j = 0; j < sampleIndex; j++){
fprintf(f, "%d,%dn", timeArray[j], sampleArray[j]);
}
fclose(f);
if(verbose){
printf("%d samples found, saving to %sn", sampleIndex,strDestPath);
}
}else{
}
}else{
if(verbose)
printf("Source binary not found, moving on to next file...n");
}
}
/* free the memory */
free(timeArray);
free(sampleArray);
if(verbose)
printf("nfreeing memory...n");
if(verbose)
printf("program execution completen");
sampleIndex
可以大于numOfSamples
,因为它在内部循环while(networkTime < endTime)
中未重新初始化为0
解决方案
确保内部for循环中的sampleIndex
永远不大于numOfSamples
。