【问题标题】:C segmentation fault Raspberry Pi2C分段错误Raspberry Pi2
【发布时间】:2015-11-03 19:29:37
【问题描述】:

我在嵌入式平台上使用 C 语言相当有经验,但我在操作系统中使用 C 语言的次数不多。我目前正在开发 Raspberry Pi 2。

我正在使用 C 语言,我需要制作一个实用程序来从二进制文件的一部分创建 CSV 文件。二进制文件包含数小时的数据,并被格式化为一系列“块”,每个“块”包含约 2000 毫秒的数据。程序是遍历每个block,拉取数据,直到到达结束时间。

当我尝试进行相对较小的二进制到 csv 的转换时,该程序可以工作,但是没有理由它不应该适用于我可以识别的较大的转换。当我以 MAX_TIME_SAMPLE_TO_CONVERT 为 180000 运行程序时,正常运行和 valgrind 都没有问题。当我将“MAX_TIME_SAMPLE_TO_CONVERT”更改为 200000 时,即出现分段错误。这只需要 60kB 内存的 malloc,这应该是轻而易举的事。当我从命令行运行“免费”时,我有超过 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: %dms\n", 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 samples\n");
        printf("\ttime window truncated to %dms\n", timeWindow);
        printf("\tnew end time: %d\n", 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 samples\n", 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: %d\n", 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,%d\n", timeArray[j], sampleArray[j]);
            }

            fclose(f);

            if(verbose){
                printf("%d samples found, saving to %s\n", 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 complete\n");

【问题讨论】:

  • 这是什么:sampleArray[sampleIndex] = uncompressedBlockDataArray[j];**
  • 错字 - 我打算突出显示该区域并错过了删除那些
  • 如果for循环条件应该是&amp;&amp; time &lt; timeAtEndOfBlock? ...如果不是,numSamples 是否大于 MAX_BLOCK_SIZE_IN_BYTES/2
  • “完整代码”没有main函数等。如何发布代码请看this page,尤其是当您希望别人为您调试时。

标签: c segmentation-fault raspberry-pi malloc raspberry-pi2


【解决方案1】:

sampleIndex 可以大于 numOfSamples,因为它没有在内循环中重新初始化为 0 while(networkTime &lt; endTime)

解决方案

确保在您的内部 for 循环中 sampleIndex 永远不会大于 numOfSamples

【讨论】:

  • 虽然此信息可能会有所帮助,但您最好将其放在评论中,或对其进行改进以包含答案。这只会告诉他们出了什么问题,而不是告诉他们如何解决。
  • 感谢您的宝贵时间。 “sampleIndex”旨在为相对较大的数组“timeArray”和“sampleArray”存储数据。它旨在在每个数组创建开始时重置(第一个以“i”为索引的 for 循环的顶部)。在我写这篇文章时,我意识到更好的设计是将数据块直接读取到 CSV 文件中,而不是使用大块内存作为简单的缓冲区......
  • @slightlynybbled 的重点是,您需要确保不超过 timeArraysampleArray 的数组边界。
  • 我同意,我需要确保我保持在数组的范围内。这是我的问题的答案,但获得该答案的过程让我意识到我使用的 RAM 比完成任务所需的内存要多得多,但架构略有不同。谢谢大家!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-08
  • 2019-07-16
相关资源
最近更新 更多