Windows下C/C++编译调试技巧

目录

1 #define定义函数块

2 C++异常处理机制

3 常用宏/函数

3.1 判断运行模式(debug、release)

3.2 判断运行环境(win32、win64)

3.3 C++调用C库的方法

3.4 MFC下使用控制台输出调试信息

3.5 Edit控件显示日志信息

3.6 以十六进制显示内存数据

4 解决 error C2146: 语法错误: 缺少“;”(在标识符“PVOID64”的前面)

5 C++程序只允许运行一个实例


1 #define定义函数块

        C/C++ 语言中,除了可以用 #define 定义一个标识符来表示一个常量,还可以用 #define 定义函数,例如:

//定义常量
#define MAX_VALUE 100       //定义整型变量MAX_VALUE值为100
#define USER_NAME "huge"    //定义字符串变量USER_NAME值为"huge"
#define PI 3.1415926        //定义浮点数变量PI值为3.1415926

//定义简单函数
#define MAX(a,b) (a>b)?a:b  //取两个数最大值
#define MIN(a,b) (a<b)?a:b  //取两个数最小值

//定义复杂多行的函数
#define   MACRO(arg1,   arg2)   do   {   \
   \
stmt1;   \
stmt2;   \
   \
}   while(0)
//关键是要在每一个换行的时候加上一个 "\ "

        凡是以 # 开头的均为预处理指令,预处理又叫预编译。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。

        #define后面定义的内容必须在同一行,而有时是为了让程序便于阅读,从中间进行换行,如果没有符号'\',则我们的换行表示 #define的结束。如果在这里加了'\',也可以说是对"回车"的转义,表示这里有一个回车字符而已,#define并没有结束.而程序编译的时候,编译器会忽略掉这些'\回车'的字符.

        使用define定义一个多行的复杂函数,关键是要在每一个换行的时候加上一个 \

2 C++异常处理机制

        C++中的异常处理主要依靠三个关键词:trycatchthrow

  • try:包裹可能抛出异常的代码块。

  • catch:捕获并处理特定类型的异常。

  • throw:用于抛出异常对象。

try {
    // 可能抛出异常的代码
    throw std::runtime_error("发生错误");
} catch (const std::exception& e) {
    // 处理异常
    std::cerr << "捕获到异常: " << e.what() << '\n';
}
 
#include "stdafx.h"
#include "iostream"
using namespace std;
 
int test1()
{
    try 
    {
        char *p = new char[0x7fffffff]; //抛出异常
    }
    catch (exception e)
    {
        cout << e.what() << endl;  //捕获异常,然后程序结束
        return -1;
    }
    return 0;
}

int main()
{
    printf("%d\n",test1());
    return 0;
}

3 常用宏/函数

3.1 判断运行模式(debug、release)

        在Debug模式下调试程序时,有可能需要程序执行额外的操作,比如输出值,显示额外信息;但是这些信息在Release模式下是不需要的,这时候可以通过下面的代码来进行干涉。

#ifdef _DEBUG
 
#else
 
#endif // _DEBUG

3.2 判断运行环境(win32、win64)

        类似地,可以判断是否处于32位模式:

#ifdef WIN32
 
#else
 
#endif // WIN32

        其中提到的_DEBUG、WIN32不需要自己在代码中定义,已经在VS预处理器中定义好了,可以通过以下推荐查看属性管理器 -> Debug | Win32 -> 右键"属性" -> 通用属性 -> C/C++ -> 预处理器 -> 预处理器定义

3.3 C++调用C库的方法

        C++调用C的函数比较简单,直接使用extern "C" {}告诉编译器用C的规则去调用C函数就可以了。

        CAdd.h

//CAdd.h
int cadd(int x, int y);

        CAdd.c

//CAdd.c
#include "CAdd.h"
#include <stdio.h>

int cadd(int x, int y) {
    printf("from C function.\n");
    return (x + y);
}

        cppmain.cpp

//cppmain.cpp
#include <stdio.h>

extern "C" {
#include "CAdd.h"
}

int main()
{
  int sum = cadd(1, 2);
  printf("1+2 = %d\n", sum);
  return 0;
}

        这里是在include头文件的外面包裹了extern "C" { },是告诉编译器以C语言的命名方式去加载这个符号。

        还有一种比较常见的方式是在头文件中进行编译声明,如下所示,这样的话,无论C还是C++直接正常include就可以使用了。

        CAdd.h

//CAdd.h
#ifdef __cplusplus
extern "C" {
#endif

int cadd(int x, int y);

#ifdef __cplusplus
}
#endif

3.4 MFC下使用控制台输出调试信息

// 1、使用AllocConsole在MFC程序中调用控制台调试输出
//(1)打开控制台资源,重定向输出流至控制台
AllocConsole(); 
freopen("CONOUT$", "w+t", stdout);  //申请控制台输出支持
//freopen("CONIN$", "r+t", stdin);  //申请控制台输入支持
        
//(2)执行调试信息输出操作
printf("welcome to use console using printf\n"); //在程序的任意位置,如果想输入信息,都可以这样做
std::cout << "welcome to use console using std::cout" << std::endl;
//char ch = getchar(); //读数据
        
//(3)释放控制台资源,这一句放在程序退出的时候
FreeConsole();

//2、使用重定向cout.rdbuf()将调试输出打印到文件
//(1)C++标准输出流换向(cout.rdbuf()打印到文件)
ofstream fout("d:\\log.txt");  //文件输出流对象
streambuf* pOld = cout.rdbuf(fout.rdbuf());
        
//(2)在程序的任意位置,如果想输入信息,都可以这样做
std::cout << "welcome to use log_file using std::cout" << std::endl;
        
//(3)用于恢复 标准输出
cout.rdbuf(pOld); 

3.5 Edit控件显示日志信息


void CWriteToolDlg::ShowMessage(char *lpMsg,bool IsAddTime)
{
        SYSTEMTIME tm;
        GetLocalTime(&tm);
        char szTime[30] = {0};
        sprintf(szTime, "%02d:%02d:%02d", tm.wHour,tm.wMinute,tm.wSecond);
        char message[4096] = {0};
        sprintf(message,"[%s] %s",szTime,lpMsg);
        CEdit* pMsgInfo = (CEdit*)GetDlgItem(IDC_EDIT_INFO);
        pMsgInfo->SetSel(pMsgInfo->GetWindowTextLength(), 
                pMsgInfo->GetWindowTextLength());
        if (IsAddTime)
                pMsgInfo->ReplaceSel(message);
        else
                pMsgInfo->ReplaceSel(lpMsg);
        pMsgInfo->ReplaceSel("\r\n");
}

void CWriteToolDlg::ResetMessage()
{
        CEdit* pMsgInfo = (CEdit*)GetDlgItem(IDC_EDIT_INFO);
        pMsgInfo->SetWindowText("");
        pMsgInfo->Invalidate();
}

3.6 以十六进制显示内存数据


#include <stdio.h>

static void display_buffer_hex(unsigned char *buffer, unsigned size)
{
        unsigned i, j, k;

        for (i=0; i<size; i+=16) {
                printf("\n  %08x  ", i);
                for(j=0,k=0; k<16; j++,k++) {
                        if (i+j < size) {
                                printf("%02x", buffer[i+j]);
                        } else {
                                printf("  ");
                        }
                        printf(" ");
                }
                printf(" ");
                for(j=0,k=0; k<16; j++,k++) {
                        if (i+j < size) {
                                if ((buffer[i+j] < 32) || (buffer[i+j] > 126)) {
                                        printf(".");
                                } else {
                                        printf("%c", buffer[i+j]);
                                }
                        }
                }
        }
        printf("\n" );
}

4 解决 error C2146: 语法错误: 缺少“;”(在标识符“PVOID64”的前面)

        错误结果如图:

        跑程序遇见这个问题,查看错误根源说是PVOID64未定义,查找资料原因说是头文件搜索顺序引起的。

        通过添加在stdafx.h的开头,加上以下代码通过编译:

#ifndef POINTER_64  
  
#if !defined(_MAC) && (defined(_M_MRX000) || defined(_M_AMD64) || defined(_M_IA64)) && (_MSC_VER >= 1100) && !(defined(MIDL_PASS) || defined(RC_INVOKED))  
#define POINTER_64 __ptr64  
typedef unsigned __int64 POINTER_64_INT;  
#if defined(_WIN64)  
#define POINTER_32 __ptr32  
#else  
#define POINTER_32  
#endif  
#else  
#if defined(_MAC) && defined(_MAC_INT_64)  
#define POINTER_64 __ptr64  
typedef unsigned __int64 POINTER_64_INT;  
#else  
#if (_MSC_VER >= 1300) && !(defined(MIDL_PASS) || defined(RC_INVOKED))  
#define POINTER_64 __ptr64  
#else  
#define POINTER_64  
#endif  
typedef unsigned long POINTER_64_INT;  
#endif  
#define POINTER_32  
#endif  
#endif  

5 C++程序只允许运行一个实例

#define _SESSION_MUTEX_ "SESSION_MUTEX"
bool checkMyselfExist()    //如果程序已经有一个在运行,则返回true
{
    HANDLE  hMutex = CreateMutex(NULL, FALSE, _SESSION_MUTEX_ );
    if (hMutex && (GetLastError() == ERROR_ALREADY_EXISTS))
    {
        CloseHandle(hMutex);
        hMutex = NULL;
        return true;
    }
    else{
        return false;
    }
}
int main()
{
    if (checkMyselfExist()){
        cout << "program has been runnin" << endl;
    }
    else{
        cout << "start running" << endl;
    }
    system("pause");

    return 0;
}

  • 10
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值