当前位置:网站首页>C#,入门教程——程序运行时的调试技巧与逻辑错误探针技术与源代码
C#,入门教程——程序运行时的调试技巧与逻辑错误探针技术与源代码
2022-07-28 06:20:00 【深度混淆】

一、关于程序错误的概述
编程的水平,如同人之体质,主要来自于基础,数学与算法;
但编程的功力,如同人的武功或运动成绩,则主要来自于调试、测试与跟踪。
程序的错误大致可分为:语法错误、数据错误、逻辑错误
我们都知道,如果程序在哪行?哪列出现语法错误,Visual Studio 编译器会直接指出来,一瞅便知,非常方便。
编译器首先就是为解决语法错误而设计的工具。
数据错误主要出现于局部,或 接口部分。局部性的数据错误,通过设置断点,然后按 F10, F11 等快捷键的单步调试是不错的办法。
但很多无法进行单步调试的 接口型数据错误,是比较麻烦的。只能用下面的办法。
逻辑错误是致命的、也是最难跟踪与分析的。逻辑错误还是过程性错误,往往要在程序运行时才会出现。可是,如果是编译通过的程序,称为运行时代码,出现错误,怎么知道哪行?哪列?哪个函数出现问题呢?
你可能阅读了很多这方面的文章,但就 C# 而言,建议你使用 北京联高软件开发有限公司 在这里开源的 Truffer 的基础类之一:C#运行时逻辑错误探针类。
特点:
(1)直接输出哪个源代码?行号?列号?函数名?重点信息;
(2)插入 探针 与 撤销 都非常简单;
(3)可 分页 输出超过 20 亿条的探针信息,只要你的硬盘空间足够富裕;
(4)基于输出的 探针信息,可以做很多的分析(大数据);
(5)基于下面代码的Truffer Xtracer功能更多,比如可以检测 死循环,可以探测堆、栈及重要数据的超界等。

二、逻辑错误探针类(简版)
#if DEBUG
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Legalsoft.Truffer
{
public static class zz
{
private static StringBuilder sb { get; set; } = new StringBuilder();
private static string head { get; set; } = "";
private static string tail { get; set; } = "";
private static string format { get; set; } = "";
/// <summary>
/// 跟踪器的步数
/// </summary>
private static long step { get; set; } = 0;
/// <summary>
/// 每个 html 文件显示的 step 数
/// </summary>
private static long pagesize { get; set; } = 5000;
/// <summary>
/// 每隔 writesize 输出跟踪器语句(html)
/// 如果设置 writesize=0,则每个跟踪器语句都输出文件;
/// </summary>
private static long writesize { get; set; } = 100;
/// <summary>
/// 初始化
/// </summary>
private static void a()
{
if (head.Length == 0)
{
StringBuilder sx = new StringBuilder();
sx.AppendLine("<html>");
sx.AppendLine("<body>");
sx.AppendLine("<style>td { padding:5px;text-align:left; } </style>");
sx.AppendLine("<table width='100%' border=1 bordercolor='#AAAAEE' style='border-collapse:collapse;'>");
sx.Append("<tr style='background-color:#EEEEFF;'>");
sx.Append("<td>序号</td>");
sx.Append("<td>文件名</td>");
sx.Append("<td>行</td>");
sx.Append("<td>列</td>");
sx.Append("<td>函数名</td>");
sx.Append("<td>信息</td>");
sx.AppendLine("</tr>");
head = sx.ToString();
}
if (tail.Length == 0)
{
StringBuilder sx = new StringBuilder();
sx.Append("<tr style='background-color:#EEEEFF;'>");
sx.Append("<td>序号</td>");
sx.Append("<td>文件名</td>");
sx.Append("<td>行</td>");
sx.Append("<td>列</td>");
sx.Append("<td>函数名</td>");
sx.Append("<td>信息</td>");
sx.AppendLine("</tr>");
sx.AppendLine("</table>");
sx.AppendLine("</body>");
sx.AppendLine("</html>");
tail = sx.ToString();
}
if (format.Length == 0)
{
StringBuilder sx = new StringBuilder();
sx.Append("<tr>");
sx.Append("<td style='text-align:right'>{0}</td>");
sx.Append("<td>{1}</td>");
sx.Append("<td>{2}</td>");
sx.Append("<td>{3}</td>");
sx.Append("<td>{4}</td>");
sx.Append("<td>{5}</td>");
sx.AppendLine("</tr>");
format = sx.ToString();
}
}
/// <summary>
/// 探针函数
/// 调用方法为:
/// zz.z(new StackTrace(new StackFrame(true)).GetFrame(0));
/// </summary>
/// <param name="sf">堆栈帧</param>
/// <param name="info">你可以定义的任何类型的输出信息</param>
public static void z(StackFrame sf, string info = "")
{
a();
string buf = String.Format(format, step + 1, sf.GetFileName(), sf.GetFileLineNumber(), sf.GetFileColumnNumber(), sf.GetMethod().Name, info);
sb.AppendLine(buf);
if (step > 0)
{
if ((step % writesize) == 0 || writesize == 0)
{
string fn = String.Format("Z-{0:D8}.html", (int)((step - (step % pagesize)) / pagesize));
File.WriteAllText(fn, head + sb.ToString() + tail, Encoding.UTF8);
}
if ((step % pagesize) == 0)
{
sb.Clear();
sb.AppendLine(buf);
}
}
step++;
}
}
}
#endif
使用方法:
请将上面的代码保存为 Basic.Z.cs ,并加入 工程项目 project 即可。
三、探针类的使用
在原来的程序中加入适当的探针代码,然后运行程序即可输出 Z-0000000.html 这样的页面文件,可以直接用浏览器阅读,了解程序调用的顺序,并分析可能存在的逻辑问题。
1、探针插入
在需要记录(探测)的位置,插入下面这个语句:
#if DEBUG
zz.z(new StackTrace(new StackFrame(true)).GetFrame(0));
#endif
或者带重要信息(跟踪 begin end 的数据变化):
#if DEBUG
zz.z(new StackTrace(new StackFrame(true)).GetFrame(0), begin + ", " + end);
#endif
完整的代码示例:
...
using Legalsoft.Truffer;
namespace Legalsoft.DeepConfiser
{
public class TokenScanner
{
/// <summary>
/// 将全部令牌(tokens)
/// 按 {} 粗略划分到的层次型块(block)
/// (深度优先遍历的递归算法)
/// </summary>
/// <param name="parent"></param>
/// <param name="tokens"></param>
/// <param name="begin"></param>
/// <param name="end"></param>
public void Segmentation(Block parent, List<Token> tokens, int begin, int end)
{
#if DEBUG
zz.z(new StackTrace(new StackFrame(true)).GetFrame(0), begin + ", " + end);
#endif
if (tokens[begin].Buffer == "{" && tokens[end].Buffer == "}")
{
begin++;
end--;
}
...
}
}
}
2、探针的撤销

编译选项 #if DEBUG ,仅仅适用于调试模式的编译结果;对于 RELEASE 的编译版本而言,其中的 exe 文件是不含有 探针的,也不会输出 Z-00000000.html 文件,因而,一般来说,你无需刻意去删除(撤销)前面加入的探针代码。
小药治大病。
边栏推荐
- (Reprinted) plantuml Quick Guide
- Redis of non relational database [jedis client +jedis connection cluster]
- Deep browser rendering principles
- js卡通英文字母打字小游戏源码
- JS card cascading style image switching JS special effect
- Awk from introduction to earth (16) discussion on the types of awk variables -- about the two types of numbers and strings
- 03 | project deployment: how to quickly deploy a website developed based on the laravel framework
- OSPF comprehensive experiment (7.12)
- A group of South University students rely on science and technology to go to sea, with an annual income of 1billion
- Yaml parameter configuration based on singleton mode
猜你喜欢

单片机IO口控制12V电压通断,MOS和三极管电路

DNA modified noble metal nanoparticles | DNA modified copper nanoparticles cunps-dna | research points

Prescan quick start to master the track editing path of Lecture 16

华为高级工程师---BGP路由过滤及社团属性

【花书笔记】 之 Chapter01 引言

Change the dataDir path after mysql8.0.16 installation

protobuf 基本语法总结

Prescan quick start to master the transportation elements in lesson 14, prescan

使用FFmpeg来批量生成单图+单音频的一图流视频
![[leetcode] 24. Exchange nodes in the linked list in pairs](/img/06/af8cffd306777b14a4989e638f5866.png)
[leetcode] 24. Exchange nodes in the linked list in pairs
随机推荐
Understand CDN
谈谈DOM0,DOM1,DOM2,DOM3
Detailed explanation of random number generated by random class
mysql,我们如何得到受查询影响的行数?
解决CNN固有缺陷!通用 CNN 架构CCNN来了| ICML2022
Yaml parameter configuration based on singleton mode
Es6: template string
Find out whether the number exists from the matrix
Record a MYCAT connection and solve the problems of communications link failure
Qt多线程中槽函数在哪个线程里执行分析
[300 + selected interview questions from big companies continued to share] big data operation and maintenance sharp knife interview question column (VIII)
Allure use
非关系型数据库之Redis【redis安装】
Awk from introduction to earth (16) discussion on the types of awk variables -- about the two types of numbers and strings
Oracle local network service
Mysql, how can we get the number of rows affected by the query?
JS candy xiaoxiaole game source code
JS cartoon English alphabet typing game source code
Some experience of gd32 using Hal Library of ST and Gd official library
[dry goods] 32 EMC standard circuits are shared!