C语言无if三维点八分域计数实现及2^24规模点数组填充问题
问题原因分析
栈溢出错误成因
你定义的pnt arr[(1 << 24)]是局部栈上数组,2^24等于16777216个点,每个点占3个float共12字节,总大小约192MB,而操作系统给程序栈分配的内存通常只有8MB~32MB,远不足以容纳这么大的数组,因此触发栈溢出。
Release模式不执行代码原因
栈上分配超大数据属于未定义行为,Release模式下编译器检测到该非法操作,会直接优化删除相关代码段,因此看起来for循环和count函数没有执行。
正确实现方案
n=2^24的要求是指定测试用的点数量为16777216,用于放大两个版本的性能差异,你只需要把大数组从栈上分配改为堆上动态分配即可,具体实现如下:
1. 无if版统计函数实现
根据提示,八分域索引的每一位对应一个维度的正负判断:x非负对应索引第2位(值4)、y非负对应第1位(值2)、z非负对应第0位(值1),利用C语言布尔表达式返回1/0的特性直接拼接索引,全程无需if语句:
#include <string.h> void count_no_if(pnt const* pnts, const int n, unsigned cnt[8]) { memset(cnt, 0, sizeof(unsigned) * 8); for (int i = 0; i < n; ++i) { int idx = ((pnts[i][0] >= 0.0f) << 2) | ((pnts[i][1] >= 0.0f) << 1) | (pnts[i][2] >= 0.0f); cnt[idx]++; } }
2. 大数组分配与填充代码
改用malloc在堆上分配数组空间,堆内存上限远大于栈,完全可以容纳192MB的点数组:
#include <stdlib.h> #include <stdio.h> int main() { const int n = 1 << 24; // 堆上分配点数组 pnt* arr = (pnt*)malloc(sizeof(pnt) * n); if (arr == NULL) { printf("内存分配失败\n"); return 1; } // 填充随机点,注意循环边界修正为i < n for (int i = 0; i < n; i++) { for (int j = 0; j < 3; j++) { arr[i][j] = (float)((rand() % 100) - 50); } } unsigned cnt[8]; // 测试两个版本的性能 count(arr, n, cnt); // count_no_if(arr, n, cnt); // 释放内存 free(arr); return 0; }
性能对比注意事项
- 测试时建议开启编译器O2优化,避免调试信息干扰性能结果
- 可以多次调用函数取平均耗时,降低随机误差
- 带if版本因为分支不可预测,分支预测失败率高,性能会显著低于无分支版本
内容的提问来源于stack exchange,提问作者Leon
相关产品推荐
相关产品推荐

