颜色识别项目MFC界面问题汇总

MFC开发中遇到的问题

①decoderLogin(ip, user, code)函数返回值不为0

一般由于摄像头登录失败引起。
error返回错误码为3:SDK未初始化
解决办法:
在MainApp中初始化SDK

	//初始化摄像头
	bool tmp = SDK_Init();			

海康威视错误码表
https://open.hikvision.com/hardware/definitions/NET_DVR_GetLastError.html

②PinNetCheck一直返回false

涉及到ping ip问题的部分有:
1.MainApp属性页->链接器->输入->附加依赖项加入ws2_32.lib,取消勾选从父类或项目默认设置继承;
2.MainApp属性页->C/C+±>常规->SDL检查设置否;
3.PinNetCheck.h中加入:

	#include 
	#pragma  comment (lib, "ws2_32.lib")	

PinNetCheck.cpp中使用:

	WSADATA WSAData;
	WSAStartup(MAKEWORD(1, 1), &WSAData);
	rawSocket = WSASocket(AF_INET,
						  SOCK_RAW,
						  IPPROTO_ICMP,
						  NULL, 0, 0);

rawSocket一直返回2^64-1适用这条;

③项目VC目录,数据库纪要

颜色识别项目MFC界面问题汇总_第1张图片
颜色识别项目MFC界面问题汇总_第2张图片
颜色识别项目MFC界面问题汇总_第3张图片
颜色识别项目MFC界面问题汇总_第4张图片
颜色识别项目MFC界面问题汇总_第5张图片
颜色识别项目MFC界面问题汇总_第6张图片
颜色识别项目MFC界面问题汇总_第7张图片
颜色识别项目MFC界面问题汇总_第8张图片

④ VS2015调整布局界面卡死

来源于windows更新兼容性问题,卸载KB5000803后恢复

颜色识别项目MFC界面问题汇总_第9张图片

⑤无法启动此程序,因为计算机中丢失opencv_world341.dll。请尝试重新安装改程序已解决此问题。

把opencv底下E:\opencv\build\x64\vc14\bin的文件opencv_world341.dll复制到电脑C:\Windows\System32底下

⑥项目运行提示找不到cv::xx函数

一般是链接错了动态库文件,或者没正确include
1.在release环境下附加依赖项应该选择opencv_world451.lib;debug模式下应该为opencv_world451d.lib。
2.opencv目录找到这个函数在的文件,将其加入项目文件表头,例:

#include 
#include 

⑦项目程序退出后出现大量内存泄漏的警告

颜色识别项目MFC界面问题汇总_第10张图片
实践证明,这是误报的内存泄漏。
链接: 解决MFC使用OpenCV动态库会误报内存泄露的问题。
采用方法二成功解决。

链接1: 简单内存泄漏检测方法 解决 Detected memory leaks! 问题.
链接2: 内存管理:_CrtDumpMemoryLeaks和_CrtSetBreakAlloc.

检查是否资源泄漏的办法之一:
在任务管理器 进程 查看 选择列 里面选择:内存使用、虚拟内存大小、句柄数、线程数、USER对象、GDI对象
让你的程序(进程)不退出,循环执行主流程很多遍,越多越好,比如1000000次甚至无限循环,记录以上各数值,再隔至少一小时,越长越好,比如一个月,再记录以上各数值。如果以上两组数值的差较大或随时间流逝不断增加,则铁定有对应资源的资源泄漏!搜“GDI泄露检测”

⑧opencv4.0中“未定义标识符cvNamedWindow或CV_WINDOW_AUTOSIZE”的解决方法

比如:“在代码开头加入头文件#include ”之类的方法,就完全没解决问题。

经过探索,终于找到了解决之道。

原来这是由于opencv4.0和之前的版本中有一些命令发生了变化,比如在之前的版本中cvNamedWindow是用来创建窗口的,然而到了4.0版本中,创建窗口的命令改成了namedWindow,所以只要把命令替换以下就可以运行了。

同样的老版本中“cvResizeWindow”改成了“resizeWindow”。类似的情况还有很多,就不一一列举了。
opencv3以后CV_XXX_XXX函数,改为了XXX_XXX,去掉前面的CV_就是新版本中同样的。
————————————————
版权声明:本文为CSDN博主「Leroy Sane」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接: Link

⑨OpenCV 行列值与坐标的对应关系

OpenCV像素坐标系如下图所示:
颜色识别项目MFC界面问题汇总_第11张图片
*行列与坐标系对应关系
行:Y
列:X
注意!注意!注意!
在Mat类型变量访问时下标是反着写的,即:按照(y, x)的关系形式访问,下面通过代码展示来说明这一点

下面展示一些 代码片

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

#include 

using namespace cv;
using namespace std;

int main()
{
    Mat mat_src = Mat::eye(3, 4, CV_8UC1);

    cout << "mat_src :" << endl;
    cout << mat_src    << endl;

    cout << endl;
    cout << "Rows : " << mat_src.rows << endl;
    cout << "Cols : " << mat_src.cols << endl;

    //注: mat_src.at(y, x), 下标关系为: y-x
    mat_src.at<float>(0, 2) = 2; 
    mat_src.at<float>(2, 0) = 4;

    cout << endl;
    cout << "mat_src :" << endl;
    cout << mat_src    << endl;

    return 0;
}

执行结果:
颜色识别项目MFC界面问题汇总_第12张图片
转载至: link.

⑩opencv的Copyto函数

首先对于openCv中copyTo()的用法有以下两种:

image.copyTo(imageROI)。作用是把image的内容复制粘贴到imageROI上;

image.copyTo(imageROI,mask)。 作用是把mask和image重叠以后把mask中像素值为0(black)的点对应的image中的点变为透明,而保留其他点。

⑩①多线程单类多变量实现多窗口中其它窗口给此类发消息无法传递的BUG

项目体系如下:
主窗口类为CMainDlg,分别创建三个CCameraThread线程类对象,在三个线程对象中分别创建子窗口类CCamera对象。
此时CCamera类下有子窗口类CExtractDlg,当从CExtractDlg类中使用SendMessage发送消息时:

	CCamera* p = (CCamera*)GetParent();
	int b = p->m_targetInfo.number;
	LRESULT a = ::SendMessage(p->GetSafeHwnd(), DESTROYDLG, 1, 0);
	// 此处加断点后,a=0,b=2071849968
	//正常情况应为,a为非零值,b = 摄像头编号

这个BUG是由于项目结构导致

	CCamera* p = (CCamera*)GetParent();

语句找不到具体对象,返回新的一个CCamera类对象。
发送消息修改为如下后可正常发送消息:

pDlg->m_Thread2->m_Dlg1->SendMessage(DESTROYDLG, NULL, NULL);
//pDLg是CMainDlg类指针,m_Thread2是CCameraThread类对象
//m_Dlg1是CCamera对象,对应摄像头1

⑩②海康工业相机SDK开发资料

这是黑色摄像头的!海康威视工业相机
机器型号MV-CA060-10GC,工业相机网址不在海康官网,要搜索HIKROBOT
SDK开发见如下链接:
链接: 海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(一).

链接: 海康威视工业相机SDK二次开发.

⑩③海康工业相机MVS抓图并转换为mat

下面展示一些 内联代码片

Mat CameraSDK::getM_pic()
{
	m_nSaveImageType = MV_Image_Bmp;
	int nRet = SaveImage();
	if (!nRet)
	{
		bool isMono;//判断是否为黑白图像
		switch (stImageInfo.enPixelType)
		{
		case PixelType_Gvsp_Mono8:
		case PixelType_Gvsp_Mono10:
		case PixelType_Gvsp_Mono10_Packed:
		case PixelType_Gvsp_Mono12:
		case PixelType_Gvsp_Mono12_Packed:
			isMono = true;
			break;
		default:
			isMono = false;
			break;
		}

		if (isMono)
		{
			m_pic = Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC1, m_pBufForDriver);
		}
		else
		{
			//转换图像格式为BGR8
			MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 };
			memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
			stConvertParam.nWidth = stImageInfo.nWidth;
			stConvertParam.nHeight = stImageInfo.nHeight;
			stConvertParam.pSrcData = m_pBufForDriver;
			stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;
			stConvertParam.enSrcPixelType = stImageInfo.enPixelType;
			stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed;
			//stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed;
			stConvertParam.pDstBuffer = m_pBufForSaveImage;
			stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage;
			m_pcMyCamera->ConvertPixelType(&stConvertParam);
			m_pic = Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3, m_pBufForSaveImage);
			//bool result = imwrite("test1.png",m_pic);
			return m_pic;
		}
		ShowErrorMsg(TEXT("failed"), nRet);
		return m_pic;
	}

}
// 保存图片 
int CameraSDK::SaveImage()
{
	// ch:获取1张图
	unsigned int nRecvBufSize = 0;
	int nRet = MV_OK;

	// ch:仅在第一次保存图像时申请缓存,在 CloseDevice 时释放
	if (NULL == m_pBufForDriver)
	{
		// ch:从相机中获取一帧图像大小 
		nRet = m_pcMyCamera->GetIntValue("PayloadSize", &nRecvBufSize);
		if (nRet != MV_OK)
		{
			ShowErrorMsg(TEXT("failed in get PayloadSize"), nRet);
			return nRet;
		}
		// ch:一帧数据大小
		m_nBufSizeForDriver = nRecvBufSize;
		m_pBufForDriver = (unsigned char *)malloc(m_nBufSizeForDriver);
		if (NULL == m_pBufForDriver)
		{
			ShowErrorMsg(TEXT("malloc m_pBufForDriver failed, run out of memory"), 0);
			return nRet;
		}
	}

	stImageInfo = { 0 };
	memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));

	unsigned int nDataSize = nRecvBufSize;
	unsigned int nImageNum = 1;
	unsigned int nDataLen = 0;

	while (nImageNum)
	{
		nRet = m_pcMyCamera->GetOneFrameTimeout(m_pBufForDriver, &nDataLen, m_nBufSizeForDriver, &stImageInfo, 1000);
		if (nRet == MV_OK)
		{
			nImageNum--;

			// ch:仅在第一次保存图像时申请缓存,在 CloseDevice 时释放
			if (NULL == m_pBufForSaveImage)
			{
		// ch:BMP图片大小:width * height * 3 + 2048(预留BMP头大小)
				m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;

				m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage);
				if (NULL == m_pBufForSaveImage)
				{
					break;
				}
			}
			// ch:设置对应的相机参数 | en:Set camera parameter
			MV_SAVE_IMAGE_PARAM_EX stParam = { 0 };
			stParam.enImageType = m_nSaveImageType;
			 // ch:需要保存的图像类型 | en:Image format to save
			stParam.enPixelType = stImageInfo.enPixelType;  
			// ch:相机对应的像素格式 | en:Camera pixel type
			stParam.nWidth = stImageInfo.nWidth;         
			// ch:相机对应的宽 | en:Width
			stParam.nHeight = stImageInfo.nHeight;         
			 // ch:相机对应的高 | en:Height
			stParam.nDataLen = stImageInfo.nFrameLen;
			stParam.pData = m_pBufForDriver;
			stParam.pImageBuffer = m_pBufForSaveImage;
			stParam.nBufferSize = m_nBufSizeForSaveImage;  
			// ch:存储节点的大小 | en:Buffer node size
			stParam.nJpgQuality = 80;       
			// ch:jpg编码,仅在保存Jpg图像时有效。保存BMP时SDK内忽略该参数
											
			nRet = m_pcMyCamera->SaveImage(&stParam);
			if (MV_OK != nRet)
			{
				break;
			}
		}
		else
		{
			break;
		}
	}
	return nRet;
}

⑩④ 使用CreateThread方式创建线程的问题

下面展示一些 内联代码片

//全局声明线程
DWORD WINAPI PingNetThread(LPVOID lpParam);
//在代码中启动线程
HANDLE h_ping = CreateThread(NULL,0, PingNetThread, this, 0, NULL);
CloseHandle(h_ping);

CreateThread的线程无法手动关闭,只能通过系统关闭自动关闭,若在线程中与对话框类有交互,并有“sleep+循环”的形式,如:

	CCamera *p = (CCamera*)lpParam;
	//使用了CCamera对话框类
	while (p != NULL)
	{//while循环
	 ……
	 Sleep(1000);
	}

当系统关闭时可能线程正处在执行之中,而相对应的p对象被delete了,导致内存访问错误。debug发现,当注释sleep函数时,代码循环速度快,从而能通过while判断语句调查发现p对象空了。暂时找不到其他办法,只能在循环中多加入几次if(p!=NULL)的判断。

⑩⑤ CPP程序调用MATLAB ENGINE的问题

环境配置:
cpp项目包含目录下:
D:\program files\Matlab2016a\extern\include\win64
D:\program files\Matlab2016a\extern\include
cpp项目库目录下:
D:\program files\Matlab2016a\extern\lib\win64\microsoft
系统环境变量下PATH
D:\program files\Matlab2016a\bin\win64
链接器输入附加依赖项
libeng.lib
libmx.lib
libmat.lib
mclmcrrt.lib
libmex.lib
出现引擎调用失败问题
原因主要是matlab在安装时并未初始注册;
解决方案:用管理员权限打开cmd,cd到matlab目录输入命令:matlab /regserver
c文件头

#include "engine.h"

	Engine *m_engine;  //创建Matlab引擎
	//m_engine = NULL;   //初始化引擎

	if ( !(m_engine = engOpen("\0")) ) //打开引擎,此时会打开一个Matlab命令行窗口
	{
		cout << "Can't start Matlab engine!" << endl;
		exit(1);
		return 0;
	}
	engSetVisible(m_engine, 0); //将命令行窗口设为不可见
	char engBuffer[256] = { '\0' };

	engEvalString(m_engine, "cd('E:\\Color_correction')"); //进入Matlab代码的路径  
	engEvalString(m_engine, "[color_ms_e] = bptest2();");
	mxArray *result = engGetVariable(m_engine, "color_ms_e");  // 2. get the result
	double *p = mxGetPr(result); //p[0]就是计算结果
	cout << "C++ output: the sum of all the elements is: " << p[0] << endl;
	mxDestroyArray(result);
	if (m_engine)  //关闭Matlab引擎
	{
		engClose(m_engine);
		m_engine = NULL;
	}
	return 0;

⑩⑥ 海康威视网络摄像头SDK开发

目录配置如③所示;
在【附加依赖项】中添加:

HCNetSDK.lib
GdiPlus.lib
HCAlarm.lib
HCCore.lib
HCGeneralCfgMgr.lib
HCPreview.lib
PlayCtrl.lib

颜色识别项目MFC界面问题汇总_第13张图片

动态库添加到可执行文件目录:E:\MFC\test\opencvtest\x64\Debug

AudioRender.dll
HCCore.dll
HCNetSDK.dll
PlayCtrl.dll
SuperRender.dll

参考链接:海康威视摄像机的实时读取篇二(海康SDK开发环境配置)

⑩⑦ WaitForSingleObject一直阻塞

对图像处理线程:

if (m_pic != NULL)//确保线程不在挂起状态
	{
		int liv_tmp = ResumeThread(m_pic->m_hThread);
		while (liv_tmp >= 1)
		{
			liv_tmp = ResumeThread(m_pic->m_hThread);
		}
		m_exitPicThread = true;
		m_pic->PostThreadMessage(WM_QUIT, NULL, NULL);
		WaitForSingleObject(m_pic->m_hThread, INFINITE);	//无限长
	}

WaitForSingleObject设置为无限长时,程序一直阻塞,无法正常退出。
这是由于 WaitForSingleObject会阻塞对话框线程(Dialog thread),同时也会导致了对话框的消息循环机制被阻塞
而我在线程函数中会对对话框有一些UI操作(SetPos, SetWindowText),这些对对话框的UI操作实际上是通过线程向控件发送消息得到的 ( SendMessage(m_hWnd, PBM_SETPOS, nPos, 0L) )。
因此WaitForSingleObject阻塞了消息循环,也就导致 SendMessage无法返回,卡住了线程 ,WaitForSingleObject也就无法返回了。

p->set_colorpic(_Result);//此处用到了 SetWindowText

解决办法:
对话框中WaitForSingleObject等待线程退出导致程序阻塞的原因及解决;
链接2.

DWORD dwRet = 0;
		MSG msg;
		while (TRUE)
		{
			dwRet = WaitForSingleObject(m_pic->m_hThread, 500);
			switch (dwRet)
			{
			case WAIT_OBJECT_0:
				break; //break the loop  
			case WAIT_TIMEOUT:
				PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
				continue;
			default:
				break; // unexpected failure  
			}
			break;
		}

根据上面的流程,合理的解释应该是:MsgWaitForMultipleObject等待过程中Worker thread仍然被阻塞,当Dialog中有消息到来时MsgWaitForMultipleObject返回,此时调用PeekMessage,消息处理函数被激活,处理 PBM_SETPOS消息,workder thread中的SetPos函数返回。
然而,究竟是怎么样 PeekMessage会激活消息处理函数?我思考了很久在《windows核心编程》第26章“窗口消息”找到了答案:
对于接收消息的线程而言(本文中为 Dlg thread ),如果该线程正在执行代码,并且没有等待消息 (如调用GetMessage、PeekMessage或WaitMessage)时,发送过来的消息不会被该线程处理,而发送消息的线程(本文中为worker thread)中的SendMessage函数也不会返回。

根据上面的文字,也就是说,在执行 对话框中某个函数时,如果函数没有退出,并且没有执行 GetMessage、PeekMessage或WaitMessage函数,那么从别的线程发送来的SendMessage来的消息将不会被处理。

也就是说,PeekMessage这个函数所做的工作不止是从队列中拿出posted message,还在此之前会先处理nonqueued messages(send message)
找到了send message的处理流程,也就不难解释上面程序执行的流程了。

还可以看出:MsgWaitForMultipleObjects实际上在这其中并没有起到什么实质性的作用,只是定期返回而已,那么根据此,可以用固定时间WaitForSingleObject来代替MsgWaitForMultipleObjects ,并且循环等待 ;
同时,我们也没有必要手动DispatchMessage,只需要PeekMessage即可,需要注意的是如果删除了 DispatchMessage, 在 PeekMessage时不能将消息从队列取走。

————————————————
版权声明:本文为CSDN博主「silvervi」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/silvervi/article/details/5874212

⑩⑧ 程序退出时线程报异常

项目中有一个界面类的工作线程中用到了另一个界面类的变量,当程序在退出时,VS反馈异常在

pWnd = GetGDlgItem(IDC_CAMERA1_COLOR1);//参数为控件ID
pWnd->GetClientRect(&rc);//rc为控件的大小。

这句,提示GetGDlgItem函数获取的句柄为空;初步判断为此时界面已经注销,控件已经销毁。

第一,OnOK()和OnCancel()是CDialog基类的成员函数,而OnClose()和OnDestroy()是CWnd基类的成员函数,即WM消息响应函数。从应用程序结构的角度,拿对话框来说,红色的X对应的是CWnd,而处于对话框中的“确定”、“取消”按钮则对应了CDialog。

第二,OnClose()和OnDestroy()
在单视图程序中,根据<<深入浅出MFC>>所讲,程序退出时执行的操作顺序为(从点X按钮开始)
(1)用户点击X退出按钮,发送了WM_CLOSE消息----->响应OnClose()
(2)在WM_CLOSE消息的处理函数中,调用DestroyWindow()----->销毁与指定CWnd窗口对象关联的窗口,但未销毁CWnd对象
(3)在DestroyWindow()中发送了WM_DESTROY消息----->窗口销毁后响应OnDestroy()
(4)在WM_DESTROY消息中调用PostQuitMessage(),发送WM_QUIT消息,结束消息循环
可以看到,程序的退出过程,是先响应OnClose(),然后响应OnDestroy(),在响应OnDestroy()之前,窗口对象已经被销毁。OnDestroy()到底干了什么呢?它就像一个teller,先通知CWnd对象告诉它即将被销毁,尔后OnDestroy的真正运行是在CWnd对象已经从屏幕上清除以后被调用的。

第三,OnOK()、OnCancel()()、OnClose()、OnDestroy()
CDialog::OnOK首先调用UpdateData(TRUE)将数据传给对话框成员变量,然后调用CDialog::EndDialog关闭对话框;
CDialog::OnCancel只调用CDialog::EndDialog关闭对话框;
OnClose()是响应 WM_CLOSE 的.一定程度上可以说CDialog::EndDialog()和OnClose()完成类似的工作,但处理的机制不一样,前者是CDialog的对象机制,后者是WM的消息映射机制。
CDialog::EndDialog()-------->OnDestroy()
OnClose()-------->OnDestroy()
EndDialog()和OnClose()属于“同级别”的,所以我们在按下OK按钮的时候,程序是不会执行OnClose()的,但两种机制都必须经过OnDestroy()。

因此线程的退出得先放在OnDestroy()消息响应中,从而可以调整不同对话框中线程退出的顺序。若放在对话框类析构函数中进行,则会产生对话框已经销毁但线程还未退出的错误!

⑩⑨ static和const

static局部变量 将一个变量声明为函数的局部变量,那么这个局部变量在函数执行完成之后不会被释放,而是继续保留在内存中
static 全局变量 表示一个变量在当前文件的全局内可访问
static 函数 表示一个函数只能在当前文件中被访问
static 类成员变量 表示这个成员为全类所共有
static 类成员函数 表示这个函数为全类所共有,而且只能访问静态成员变量
(1)函数体内static变量的作用范围为该函数体,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
(2)在模块内的static全局变量和函数可以被模块内的函数访问,但不能被模块外其它函数访问;
(3)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
(4)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。

const 常量:定义时就初始化,以后不能更改。
const 形参:func(const int a){};该形参在函数里不能改变
const修饰类成员函数:该函数对成员变量只能进行只读操作
(1)阻止一个变量被改变
(2)声明常量指针和指针常量
(3)const修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量;
(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为”左值”。

②〇 栈空间

一个由C/C++编译ling的程序占用的内存分为以下几个部分:
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

在单元测试时,发现了比较多的线程堆栈空间不够导致 COREDUMP 的问题,这个问题的原因是由于线程独立拥有一个可配置大小的堆栈,一个线程内所有函数使用到的堆栈都依赖于这个栈,如果太多的变量、参数需要使用栈,可能 导致栈溢出从而COREDUMP。目前基础平台子系统通过配置环境变量,将默认堆栈大小设置为128K,可以减少这个问题的出现,但业务系统在编码时仍然 需要注意栈的使用,避免出现问题。
包括:
1、不要在函数内部定义过大的局部变量,如过大的结构体变量,联合变量,过大的字符串,数组等;
2、函数调用的深度也需要注意,如果函数 A 调用 B, B 再调用 C,而A/B/C每个函数定义了 10 K的局部变量,则总的栈空间需求将超过 30K;
3、不要直接将大的结构变量通过函数参数传递,这样也会消耗栈空间,可以通过指针或者引用的方式传递;
4、在unit_test/callsvc 目录下提供了一个 rs 程序,可以 misc16_pkg.h 和 particle_stru.h 中结构局部变量的大小,如果一个函数中使用了这里边的结构定义局部变量,可以通过 “rs [变量类型] ”计算总的栈内存需求。建议每个函数内部定义的变量大小控制在4-8K以下;
5、如果在运行中 COREDUMP,并且通过 GDB 的 WHERE 命令时看到刚进入某个函数就报错,连函数内的第一条调试语句都无法指向,则基本可以认为是栈空间不够导致的,可以尝试将栈空间配置大一点,如果问题不再出现,则可以确定问题。这时需要按照前面几点的要求修改代码,减少栈的使用。
颜色识别项目MFC界面问题汇总_第14张图片
颜色识别项目MFC界面问题汇总_第15张图片

链接: 设置线程堆栈大小
链接: Stack overflow 编译能通过,运行时出现Stack overflow

你可能感兴趣的:(项目MFC,mfc)