GDAL C++ API 学习之路 (2) GDALRasterBand篇 代码示例 翻译 自学
GDALRasterBand Class <gdal_priv.h>
GDALRasterBand是GDAL中用于表示栅格数据集中一个波段的类。栅格数据集通常由多个波段组成,每个波段包含了特定的数据信息,例如高程、红、绿、蓝色等,
用于表示影像的不同特征。提供了许多功能来访问和操作波段的像素数据以及相关信息。它是GDAL C++ API中处理栅格数据的核心类之一,为栅格数据处理和分析提供了强大的功能和灵活性。
Public Functions
GetLockedBlockRef
GDALRasterBlock *GetLockedBlockRef(int nXBlockOff, int nYBlockOff, int bJustInitialize = FALSE)
获取指向内部缓存栅格块的指针
参数:
-
nXBlockOff -- 水平块偏移量,零表示最左边的块,1 表示下一个块,依此类推。
-
nYBlockOff -- 垂直块偏移量,零表示最上面的块,1 表示下一个块,依此类推。
-
bJustInitialize -- 如果为 TRUE,则将分配和初始化块,但实际上不会从源读取。当它只是完全设置并写回时,这很有用。
返回: 指向块对象的指针,或失败时为 NULL
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 定义要锁定的数据块的左上角坐标int blockXOff = 0; // 数据块的起始列int blockYOff = 0; // 数据块的起始行// 获取锁定的数据块的引用GDALRasterBlock* block = band->GetLockedBlockRef(blockXOff, blockYOff);
TryGetLockedBlockRef
GDALRasterBlock *TryGetLockedBlockRef(int nXBlockOff, int nYBlockYOff)
尝试获取块引用
参数:
-
nXBlockOff -- 水平块偏移量,零表示最左边的块,1 表示下一个块,依此类推。
-
nYBlockOff -- 垂直块偏移量,零表示最上面的块,1 表示下一个块,依此类推。
返回: 如果块不可用,则为 NULL,或锁定的块指针
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 定义要锁定的数据块的左上角坐标int blockXOff = 0; // 数据块的起始列int blockYOff = 0; // 数据块的起始行// 尝试获取锁定的数据块的引用GDALRasterBlock* block = band->TryGetLockedBlockRef(blockXOff, blockYOff);
TryGetLockedBlockRef: 这个函数尝试获取指定位置的锁定数据块的引用,但不会阻塞其他线程或过程对数据块的访问。如果无法立即获取锁定的数据块引用,它将立即返回空指针(nullptr)。这样,其他线程或过程可以继续执行,而不需要等待数据块的可用性。这个函数适用于在多线程环境中使用,以避免等待和竞争条件。
GetLockedBlockRef: 这个函数也是用于获取指定位置的锁定数据块的引用,但它是一个阻塞调用。如果无法立即获取锁定的数据块引用,它将等待数据块的可用性,并一直阻塞到数据块可用为止。这意味着其他线程或过程在获取锁定数据块引用之前会被阻塞。因此,这个函数应该在单线程环境或确保不会导致竞争条件的情况下使用。总结而言,
TryGetLockedBlockRef是一个非阻塞函数,它会立即返回数据块引用(如果可用),而GetLockedBlockRef是一个阻塞函数,它会等待数据块的可用性。您应该根据具体的应用场景选择使用哪个函数。在多线程环境下,建议使用TryGetLockedBlockRef来避免阻塞其他线程。在单线程环境下,可以使用GetLockedBlockRef。
FlushBlock
CPLErr FlushBlock(int, int, int bWriteDirtyBlock = TRUE)
从块缓存中清除块
参数:
-
nXBlockOff -- 块 x 偏移量
-
nYBlockOff -- 块状偏移
-
bWriteDirtyBlock -- 如果块脏,是否应该写入磁盘。
返回: CE_None,如果成功,否则为错误代码
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 定义要写入数据块的左上角坐标int blockXOff = 0; // 数据块的起始列int blockYOff = 0; // 数据块的起始行// 获取锁定的数据块的引用GDALRasterBlock* block = band->GetLockedBlockRef(blockXOff, blockYOff);if (block != nullptr){// 在此处处理锁定的数据块// 例如,可以修改数据块的像素值// 将修改后的数据块写入数据集CPLErr err = band->FlushBlock(blockXOff, blockYOff, TRUE);if (err != CE_None){std::cout << "Error writing raster block." << std::endl;}else{std::cout << "Data block written successfully." << std::endl;}// 释放数据块的引用band->DropLock(blockXOff, blockYOff);}
GetIndexColorTranslationTo
unsigned char *GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand, unsigned char *pTranslationTable = nullptr, int *pApproxMatch = nullptr)
计算颜色表的转换表
参数:
-
poReferenceBand -- 栅格波段
-
pTranslationTable -- 一个已经分配的转换表(至少 256 个字节),或 NULL,让方法分配它
-
pApproxMatch -- 指向在匹配是近似时设置的标志的指针。可能为空。
返回: 如果两个波段是调色板索引并且它们不匹配,则为转换表,在其他情况下为 NULL。如果为 pTranslationTable 传递了 NULL,则必须使用 CPLFree 释放该表
// 获取第一个波段和参考波段(假设参考波段索引为 2)GDALRasterBand* band = dataset->GetRasterBand(1);GDALRasterBand* referenceBand = dataset->GetRasterBand(2);// 获取当前波段的颜色索引到参考波段的颜色索引的转换表int colorTableSize = band->GetColorTable()->GetColorEntryCount(); // 获取颜色表的大小unsigned char* translationTable = new unsigned char[colorTableSize];int approxMatch;band->GetIndexColorTranslationTo(referenceBand, translationTable, &approxMatch);
FlushCache
virtual CPLErr FlushCache(bool bAtClosing = false)
刷新栅格数据缓存 此调用将恢复用于缓存此栅格波段的数据块的内存,并确保将新请求引用到基础驱动程序
参数:
bAtClosing -- 这是否从 GDALDataset 析构函数调用
返回: CE_None成功
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 读取数据块或执行其他操作,导致波段的缓存被更新// 刷新波段的缓存,将缓存中的数据写入数据集CPLErr err = band->FlushCache();
GetCategoryNames
virtual char **GetCategoryNames()
获取此栅格的类别名称列表
返回: 名称列表,如果没有,则为 NULL
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的分类名称char** categoryNames = band->GetCategoryNames();
GetNoDataValue
virtual double GetNoDataValue(int *pbSuccess = nullptr)
获取此波段的无数据值
参数:
pbSuccess -- 指向布尔值的指针,用于指示值是否实际与此层相关联。可能为 NULL(默认值)。
返回: 此波段的无数据值
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的无数据值int pbSuccess;double noDataValue = band->GetNoDataValue(&pbSuccess);if (pbSuccess){std::cout << "NoData Value: " << noDataValue << std::endl;}else{std::cout << "No NoData Value found for the band." << std::endl;}
GetNoDataValueAsInt64
virtual int64_t GetNoDataValueAsInt64(int *pbSuccess = nullptr)
获取此波段的无数据值 此方法应仅在数据类型为 GDT_Int64 的栅格上调用
参数:
pbSuccess -- 指向布尔值的指针,用于指示值是否实际与此层相关联。可能为 NULL(默认值)。
返回: 此波段的无数据值
GetNoDataValueAsUInt64
virtual uint64_t GetNoDataValueAsUInt64(int *pbSuccess = nullptr)
获取此波段的无数据值。 仅应在数据类型为 GDT_UInt64 的栅格上调用此方法
GetMinimum
virtual double GetMinimum(int *pbSuccess = nullptr)
获取此波段的最小值
参数:
pbSuccess -- 指向布尔值的指针,用于指示返回值是否为紧最小值。可能为 NULL(默认值)。
返回: 最小栅格值(不包括无数据像素)
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的最小值int pbSuccess;double minValue = band->GetMinimum(&pbSuccess);if (pbSuccess){std::cout << "Minimum Value: " << minValue << std::endl;}else{std::cout << "Failed to get the minimum value for the band." << std::endl;}
GetMaximum
virtual double GetMaximum(int *pbSuccess = nullptr)
获取此波段的最大值
参数:
pbSuccess -- 指向布尔值的指针,用于指示返回值是否为紧最小值。可能为 NULL(默认值)。
返回: 最小栅格值(不包括无数据像素)
GetOffset
virtual double GetOffset(int *pbSuccess = nullptr)
获取栅格值偏移
参数:
pbSuccess -- 指向布尔值的指针,用于指示返回值是否有意义。可能为 NULL(默认值)。
返回: 栅格偏移
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的数据偏移值int pbSuccess;double offset = band->GetOffset(&pbSuccess);if (pbSuccess){std::cout << "Offset Value: " << offset << std::endl;}else{std::cout << "Failed to get the offset value for the band." << std::endl;}
GetScale
virtual double GetScale(int *pbSuccess = nullptr)
获取栅格值比例 单位值 =(原始值 * 比例)+ 偏移量
参数:
pbSuccess -- 指向布尔值的指针,用于指示返回值是否有意义。可能为 NULL(默认值)。
返回: 栅格比例
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的数据比例尺int pbSuccess;double scale = band->GetScale(&pbSuccess);if (pbSuccess){std::cout << "Scale Value: " << scale << std::endl;}else{std::cout << "Failed to get the scale value for the band." << std::endl;}
遥感影像数据:
- 灰度影像:通常使用一个常数比例尺,例如 0.1 表示每个像素值乘以 0.1 后得到实际测量值。
- 无单位浮点影像:通常使用一个常数比例尺,例如 0.01 表示每个像素值乘以 0.01 后得到实际物理量值(例如辐射亮度)。
- 有单位浮点影像:通常使用一个常数比例尺,例如 0.001 表示每个像素值乘以 0.001 后得到实际物理量值(例如温度)。
GIS 矢量数据:
- 点数据:比例尺通常用于将地理坐标(经纬度或投影坐标)转换为实际长度(例如米)。
- 线数据和多边形数据:比例尺用于将地理坐标转换为实际长度。
GetUnitType
virtual const char *GetUnitType()
返回栅格单位类型
返回: 设备名称字符串
GetUnitType()是用于获取数据单位类型的函数,而
GetRasterDataType()是用于获取像素值的数据类型的函数
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的单位类型const char* unitType = band->GetUnitType();
GetColorInterpretation
virtual GDALColorInterp GetColorInterpretation()
这条带应该如何解释为颜色
当格式对颜色解释一无所知时,将返回GCI_Undefined
返回: 波段的颜色解释值
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的颜色解释方式GDALColorInterp colorInterp = band->GetColorInterpretation();switch (colorInterp){case GCI_Undefined:std::cout << "Color Interpretation: Undefined" << std::endl;break;case GCI_GrayIndex:std::cout << "Color Interpretation: Gray Index" << std::endl;break;case GCI_PaletteIndex:std::cout << "Color Interpretation: Palette Index" << std::endl;break;case GCI_RedBand:std::cout << "Color Interpretation: Red Band" << std::endl;break;case GCI_GreenBand:std::cout << "Color Interpretation: Green Band" << std::endl;break;case GCI_BlueBand:std::cout << "Color Interpretation: Blue Band" << std::endl;break;// 其他颜色解释方式可以继续添加在这里default:std::cout << "Color Interpretation: Unknown" << std::endl;break;}
GCI_Undefined = 0, // 未定义颜色解释方式
GCI_GrayIndex = 1, // 灰度图像
GCI_PaletteIndex = 2, // 调色板索引图像
GCI_RedBand = 3, // 红色波段
GCI_GreenBand = 4, // 绿色波段
GCI_BlueBand = 5, // 蓝色波段
GCI_AlphaBand = 6, // 透明度(Alpha)波段
GCI_HueBand = 7, // 色调(Hue)波段
GCI_SaturationBand = 8, // 饱和度(Saturation)波段
GCI_LightnessBand = 9, // 亮度(Lightness)波段
GCI_CyanBand = 10, // 青色(Cyan)波段
GCI_MagentaBand = 11, // 品红色(Magenta)波段
GCI_YellowBand = 12, // 黄色(Yellow)波段
GCI_BlackBand = 13, // 黑色(Black)波段
GCI_YCbCr_YBand = 14, // YCbCr 颜色空间的 Y 波段
GCI_YCbCr_CbBand = 15, // YCbCr 颜色空间的 Cb 波段
GCI_YCbCr_CrBand = 16 // YCbCr 颜色空间的 Cr 波段
GetColorTable
virtual GDALColorTable *GetColorTable()
获取与波段关联的颜色表
如果没有关联的颜色表,则返回结果为 NULL
返回: 内部颜色表,或 NULL
// 获取第一个波段GDALRasterBand* band = dataset->GetRasterBand(1);// 获取波段的颜色表GDALColorTable* colorTable = band->GetColorTable();if (colorTable != nullptr){int numColors = colorTable->GetColorEntryCount();std::cout << "Number of Colors in Color Table: " << numColors << std::endl;// 输出颜色表中的颜色for (int i = 0; i < numColors; ++i){GDALColorEntry colorEntry;colorTable->GetColorEntryAsRGB(i, &colorEntry);std::cout << "Color " << i << ": R=" << static_cast<int>(colorEntry.c1) << ", "<< "G=" << static_cast<int>(colorEntry.c2) << ", "<< "B=" << static_cast<int>(colorEntry.c3) << std::endl;}}else{std::cout << "No color table found for the band." << std::endl;}
相关文章:
GDAL C++ API 学习之路 (2) GDALRasterBand篇 代码示例 翻译 自学
GDALRasterBand Class <gdal_priv.h> GDALRasterBand是GDAL中用于表示栅格数据集中一个波段的类。栅格数据集通常由多个波段组成,每个波段包含了特定的数据信息,例如高程、红、绿、蓝色等, 用于表示影像的不同特征。提供了许…...
springboot对静态资源的支持
1、spring boot默认静态路径支持 Spring Boot 默认将 / 所有访问映射到以下目录:** classpath:/static classpath:/public classpath:/resources classpath:/META-INF/resources也就是说什么也不用配置,通过浏览器可以直接访问这几个目录下的文件。 1…...
WPF实战学习笔记27-全局通知
新建消息事件 添加文件:Mytodo.Common.Events.MessageModel.cs using Prism.Events; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Diagnostics;namespace Mytod…...
openSUSE安装虚拟化 qemu kvm
1) 第一种:图形界面yast安装虚拟化 左下角开始菜单搜索yast 点一下就能安装,是不是很简单呢 2)第二种: 命令行安装 网上关于openSUSE安装qemu kvm的教程比较少,可以搜索centos7 安装qemu kvm的教程,然后…...
基于linux下的高并发服务器开发(第四章)- 多进程实现并发服务器(回射服务器)
1. socket // 套接字通信分两部分: - 服务器端:被动接受连接,一般不会主动发起连接 - 客户端:主动向服务器发起连接 2.字节序转换函数 当格式化的数据在两台使用不同字节序的主机之间直接传递时,接收端必然错误…...
【程序分析】符号执行
符号执行入门 参考:https://zhuanlan.zhihu.com/p/26927127 给定一个结果,求解对应的程序输入。 经典符号执行与动态符号执行 参考:https://p1kk.github.io/2021/04/04/others/%E7%AC%A6%E5%8F%B7%E6%89%A7%E8%A1%8C&%E6%B1%A1%E7%82…...
实验笔记之——Windows下的Android环境开发搭建
好久一段时间没有进行Android开发了,最新在用的电脑也没有了Android studio了。为此,本博文记录一下最近重新搭建Android开发的过程。本博文仅为本人学习记录用(**别看) 之前博客也对配置Android做过记录 Android学习笔记之——A…...
#rust taur运行报错#
场景:在window11系统上运行 tauri桌面莹应用,提示错误。 Visual Studio 2022 生成工具 安装的sdk11 , rust运行模式是stable-x86_64-pc-window-gnu, 运行npm run tauir dev 一致失败,失败信息如下 原因:1:在window11系…...
学习购药系统源码:从前端到后端的技术探索
本文将带领读者探索购药系统源码,从前端到后端逐步深入,了解其核心功能和实现方式。我们将使用常见的Web技术,包括HTML、CSS、JavaScript、以及Python的Django框架,展示购药系统的技术奥秘。 前端技术探索 HTML结构搭建 购药系…...
第九次CCF计算机软件认证
第一题:中间数 在一个整数序列 a1,a2,…,an 中,如果存在某个数,大于它的整数数量等于小于它的整数数量,则称其为中间数。 在一个序列中,可能存在多个下标不相同的中间数,这些中间数的值是相同的。 给定一个…...
【计算机网络】传输层协议 -- TCP协议
文章目录 1. TCP协议的引入2. TCP协议的特点3. TCP协议格式3.1 序号与确认序号3.2 发送缓冲区与接收缓冲区3.3 窗口大小3.4 六个标志位 4. 确认应答机制5. 超时重传机制6. 连接管理机制6.1 三次握手6.2 四次挥手 7. 流量控制8. 滑动窗口9. 拥塞控制10. 延迟应答11. 捎带应答12.…...
Mac上命令
1. block端口: sudo cp /etc/pf.conf /etc/pf443.conf 编辑pf443.conf,vim /etc/pf443.conf,如 block on en0 proto udp from any to any port 9000 # block UDP port 9000 block on en0 proto tcp from any to any port 5004 # bloc…...
软件安全测试和渗透测试的区别在哪?安全测试报告有什么作用?
软件安全测试和渗透测试在软件开发过程中扮演着不同的角色,同时也有不同的特点和目标。了解这些区别对于软件开发和测试人员来说非常重要。本文将介绍软件安全测试和渗透测试的区别,以及安全测试报告在软件开发和测试过程中的作用。 一、 软件安全测试和…...
Android 从LibVLC-android到自编译ijkplayer播放H265 RTSP
概述 ijkplayer: Android/iOS video player based on FFmpeg n3.4, with MediaCodec, VideoToolbox support. 官方的描述就这么简单的一句话,但丝毫都不影响它的强大。 从LibVLC 到 ijkplayer 截止到2023.7.20 LibVLC-Android 最大的问题在与OOM,测试了…...
如何提升等保水平,减少数据泄露率
如何提升等保水平,减少数据泄露率?随着互联网的发展和数据的普及,数据泄露已经成为了企业面临的重要安全风险之一。为了保障企业的数据安全,国家制定了《网络安全法》和《信息安全等级保护管理办法》,要求企业提升等保…...
蓝桥云课ROS机器人旧版实验报告-07外设
项目名称 实验七 ROS[Kinetic/Melodic/Noetic]外设 成绩 内容:使用游戏手柄、使用RGBD传感器,ROS[Kinetic/Melodic/Noetic]摄像头驱动、ROS[Kinetic/Melodic/Noetic]与OpenCV库、标定摄像头、视觉里程计,点云库、可视化点云、滤波和缩…...
sql入门基础-2
Dml语句 对数据的增删改查 关键字 Insert增 Update删 Delete改 添加数据 给指定字段添加数据 Insert into 表明 (字段名1,字段名2) values(值1,值2); 给全部字段添加数据--(根据位置对应添加到字段下) Insert into 表名 values…...
uni-app:实现表格多选及数据获取
效果: 代码: <template><view><scroll-view scroll-x"true" style"overflow-x: scroll; white-space: nowrap;"><view class"table"><view class"table-tr"><view class&quo…...
【图论】树上差分(点差分)
一.题目 输入样例: 5 10 3 4 1 5 4 2 5 4 5 4 5 4 3 5 4 3 4 3 1 3 3 5 5 4 1 5 3 4 输出样例:9 二 .分析 我们可以先建一棵树 但我们发现,这样会超时。 所以,我们想到树上差分 三.代码 /* 5 10 3 4 1 5 4 2 5 4 5 4 5 4 3 5 …...
【wrk2】轻量级性能测试工具
1、背景 wrk/wrk2是针对http协议的基准测试工具,特点是在单击多核CPU的前提下,通过系统自带的高性能I/O机制【epoll、kqueue等】,以多线程和事件模式,在指定的时间和请求范围下对目标机器产生负载。特点如下: 优势劣势1、安装简单、容易上手 2、基于系统自身的高性能机制…...
深入理解Android中startActivity的完整流程:聚焦IPC机制与Binder原理
引言 在Android开发中,startActivity() 方法是启动新Activity的核心API,它贯穿了应用的生命周期管理。理解其内部流程,不仅有助于优化性能、避免常见错误,还能提升开发者在面试中的竞争力。本文将以“一次完整的 startActivity 到底经历了什么”为主题,深入探讨整个流程,…...
CANN-ATB多卡推理-昇腾NPU上Llama70B怎么切到8张卡
CANN-ATB多卡推理-昇腾NPU上Llama70B怎么切到8张卡 Llama2-70B 的权重 140GB,单张 Atlas 800I A2 的 64GB 显存放不下。ATB 的多卡推理用 Tensor Parallel 把模型切到多张 NPU 上,每张卡只存 1/N 的权重和 KV Cache。 Tensor Parallel 的切法 Llama2-70B…...
1987年6月14日下午13-15点出生性格、运势和命运
这篇文章讨论终极命题:出生时间只是一个随机数据点,真正的命运由你自己书写。我们将探讨如何利用“1987年5月27日中午11-13点”这个符号,作为自我激励的起点,而非束缚。第一步:解构“出生时间”的神秘性 请明确&#x…...
STM32 USB开发避坑指南:手把手教你读懂并配置端点描述符(附完整代码)
STM32 USB开发避坑指南:手把手教你读懂并配置端点描述符(附完整代码) 在嵌入式开发领域,USB通信一直是让工程师又爱又恨的技术。爱它的通用性和高速传输能力,恨它那晦涩难懂的协议栈和层出不穷的配置问题。特别是当项目…...
自动化运维:Ansible与基础设施即代码
自动化运维:Ansible与基础设施即代码 大家好,我是欧阳瑞(Rich Own)。今天想和大家聊聊自动化运维这个重要话题。作为一个全栈开发者,自动化运维可以大大提高运维效率和可靠性。今天就来分享一下Ansible和基础设施即代码…...
AI Coding 时代的工程策略革命:为什么 Monorepo 成了 AI 的“最佳拍档“?
AI Coding 时代的工程策略革命:为什么 Monorepo 成了 AI 的"最佳拍档"? 导读:当 AI 开始替你写代码,你的工程架构是否还在"拖后腿"?本文从 AI 的视角重新审视工程策略,深度解析为什么 …...
仅剩47套!2024巴洛克风格LoRA微调模型包(附11种教堂穹顶材质映射参数表)
更多请点击: https://kaifayun.com 第一章:巴洛克美学的数字重生:LoRA微调模型包发布宣言 当黄金比例遇见梯度下降,当繁复雕花邂逅低秩矩阵分解——巴洛克精神在AI时代迎来一场静默而磅礴的复兴。本次发布的 LoRA 微调模型包并非…...
AI设计泳装,效率能翻几倍?
炎夏未至,泳装行业的备战硝烟却已弥漫。设计师灵感枯竭、打版反复修改、样衣成本高企……每一个痛点都像一座大山,压得品牌方喘不过气。面对Z世代瞬息万变的审美,“快”与“准”成了决胜关键。北京先智先行科技有限公司,正携旗下“…...
LIMA模型:仅需千条优质数据,SFT微调即可媲美GPT-4的对齐效果
1. 项目概述:LIMA的横空出世与核心价值最近,Meta AI发布了一个名为LIMA(Less Is More for Alignment)的模型,在社区里激起了不小的水花。这个项目的标题信息量巨大——“媲美GPT-4”、“无需RLHF就能对齐”,…...
Linux内核调试利器:/proc/sysrq-trigger原理与实战指南
1. 内核调试的“后门”:/proc/sysrq-trigger 深度解析在Linux内核开发和系统调试的深水区,当系统完全无响应、键盘鼠标失灵,甚至SSH连接都彻底中断时,常规的调试手段往往束手无策。这时,一个隐藏在/proc文件系统中的特…...
