gdb调试技术3

<p>本文首先以一个二叉树插入算法的实现作为例子说明GDB查看程序数据的相关方法,代码如下:</p>
<pre style="background-color: #fbfbfb; width: 650px; overflow: auto; border: 1px solid #cecece; padding: 5px;"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 1: <span style="color: #008000;">// bintree.c: routines to do insert and sorted print of a binary tree</span>

</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 2:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 3: #include
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 4: #include
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 5:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 6: <span style="color: #0000ff;">struct</span>
node {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 7: <span style="color: #0000ff;">int</span>
val; <span style="color: #008000;">// stored value</span>

</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 8: <span style="color: #0000ff;">struct</span>
node *left; <span style="color: #008000;">// ptr to smaller child</span>

</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 9: <span style="color: #0000ff;">struct</span>
node *right; <span style="color: #008000;">// ptr to larger child</span>

</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 10: };
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 11:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 12: <span style="color: #0000ff;">typedef</span>
<span style="color: #0000ff;">struct</span>
node *nsp;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 13:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 14: nsp root;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 15:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 16: nsp makenode(<span style="color: #0000ff;">int</span>
x)
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 17: {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 18: nsp tmp;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 19:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 20: tmp = (nsp) malloc(<span style="color: #0000ff;">sizeof</span>
(<span style="color: #0000ff;">struct</span>
node));
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 21: tmp->val = x;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 22: tmp->left = tmp->right = 0;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 23: <span style="color: #0000ff;">return</span>
tmp;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 24: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 25:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 26: <span style="color: #0000ff;">void</span>
insert(nsp *btp, <span style="color: #0000ff;">int</span>
x)
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 27: {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 28: nsp tmp = *btp;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 29:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 30: <span style="color: #0000ff;">if</span>
(*btp == 0) {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 31: *btp = makenode(x);
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 32: <span style="color: #0000ff;">return</span>
;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 33: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 34:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 35: <span style="color: #0000ff;">while</span>
(1)
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 36: {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 37: <span style="color: #0000ff;">if</span>
(x < tmp->val) {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 38:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 39: <span style="color: #0000ff;">if</span>
(tmp->left != 0) {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 40: tmp = tmp->left;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 41: } <span style="color: #0000ff;">else</span>
{
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 42: tmp->left = makenode(x);
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 43: <span style="color: #0000ff;">break</span>
;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 44: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 45:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 46: } <span style="color: #0000ff;">else</span>
{
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 47:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 48: <span style="color: #0000ff;">if</span>
(tmp->right != 0) {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 49: tmp = tmp->right;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 50: } <span style="color: #0000ff;">else</span>
{
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 51: tmp->right = makenode(x);
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 52: <span style="color: #0000ff;">break</span>
;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 53: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 54:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 55: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 56: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 57: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 58:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 59:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 60: <span style="color: #0000ff;">void</span>
printtree(nsp bt)
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 61: {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 62: <span style="color: #0000ff;">if</span>
(bt == 0) <span style="color: #0000ff;">return</span>
;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 63: printtree(bt->left);
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 64: printf("<span style="color: #8b0000;">%d/n</span>
",bt->val);
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 65: printtree(bt->right);
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 66: }
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 67:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 68:
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 69: <span style="color: #0000ff;">int</span>
main(<span style="color: #0000ff;">int</span>
argc, <span style="color: #0000ff;">char</span>
*argv[])
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 70: {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 71: root = 0;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 72: <span style="color: #0000ff;">for</span>
(<span style="color: #0000ff;">int</span>
i = 1; i < argc; i++)
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 73: insert(&root, atoi(argv[i]));
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 74: printtree(root);
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 75: }</pre>
</pre>
<p>在调试这个二叉树插入程序的时候,我们会非常关心insert方法的执行情况,在进入那个while(1)循环后,我们可能会做以下的操作:</p>
<blockquote>
<p>(gdb) p tmp->val
<br>
$1=12
<br>
(gdb) p tmp->left
<br>
$2 = (struct node *) 0x8049698
<br>
(gdb) p tmp->right
<br>
$3 = (struct node *) 0x0</p>
</blockquote>
<p>这个操作显得累赘又麻烦,我们可以有以下的改进措施:</p>
<p>1.<strong>直接打印结构体tmp</strong>
:</p>
<blockquote>
<p>(gdb) p *tmp
<br>
$4 = {val = 12, left = 0x8049698, right = 0x0}</p>
</blockquote>
<p><strong>2.使用display命令</strong>
:我们在#37设置断点,然后运行程序,待程序运行至该断点停下后使用
display = disp
命令对某一个变量进行监视(之所以这样做是因为这个变量必须存在在该栈帧上,也就是说调试的时候这个变量的确被创建并且没有被销毁),程序以后只要一停止
就打印这个变量的值在屏幕上:</p>
<blockquote>
<p>(gdb) disp *tmp
<br>
1: *tmp = {val = 12, left = 0x8049698, right = 0x0}
<br>
(gdb) c
<br>
Continuing.
<br>
Breakpoint 1, insert (btp=0x804967c, x=5) at bintree.c:37
<br>
37 if (x < tmp->val) {
<br>
1: *tmp = {val = 8, left = 0x0, right = 0x0}</p>
</blockquote>
<p>也可以使用dis disp 1使这个监视动作失效(enable disp 1则恢复),undisp 1为删除。info display为查看当前所有自动打印点相关的信息</p>
<p><strong>3.使用命令列表</strong>
:在<a href="http://blog.csdn.net/gnuhpc/archive/2010/12/06/6057809.aspx" target="_blank">上篇</a>
中已经叙述,在此不再赘述。</p>
<p><strong>4.使用call命令:</strong>
我们在代码中已经有了一个打印整个树的函数printtree,使用call命令我们可以直接利用代码中的方法进行变量监视,在每次insert完成的时候调用printtree对二叉树进行打印:</p>
<blockquote>
<p>(gdb) commands 2
<br>
Type commands for when breakpoint 2 is hit, one per line.
<br>
End with a line saying just "end".
<br>
>printf "*********** current tree ***********"
<br>
>call printtree(root)
<br>
>end</p>
</blockquote>
<p><strong>5.使用DDD的Data Window图形化表示</strong>
:单击右键在root这个变量上然后选择display
*root,每次在#37行停下时,在Data Window内对整个树的都有图形化表示,在左右子树上,你可以使用右键单击然后选择Display
*()来显示。(Tips:你可以以--separate参数启动DDD,这样每个Window都是独立的,你可以获得更大的视野)。</p>
<p>补充:</p>
<p><strong>1.打印数组:</strong>
p<strong> </strong>
<a href="mailto:*pointer@number_of_elements">*pointer@number_of_elements</a>
,其中number_of_elements表示显示pointer这个变量中的几个成员。另外一种方式是类型转换,例如下列程序:</p>
<pre style="background-color: #fbfbfb; width: 650px; overflow: auto; border: 1px solid #cecece; padding: 5px;"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 1: <span style="color: #0000ff;">int</span>
*x;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 2: main()
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 3: {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 4: x = (<span style="color: #0000ff;">int</span>
*) malloc(25*<span style="color: #0000ff;">sizeof</span>
(<span style="color: #0000ff;">int</span>
));
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 5: x[3] = 12;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 6: }</pre>
</pre>
<p>除了可以使用:</p>
<blockquote>
<p>(gdb) p *x@25
<br>
$1 = {0, 0, 0, 12, 0 }</p>
</blockquote>
<p>我们还可以使用:</p>
<blockquote>
<p>(gdb) p (int [25]) *x
<br>
$2 = {0, 0, 0, 12, 0 }</p>
</blockquote>
<p><strong>2.打印本地变量</strong>
:info locals,会打印当前栈帧的本地变量。</p>
<p><strong>3.以不同形式打印变量</strong>
:p/paramenters variable parameters 可以是 x 表示打印变量以十六进制表示,f为浮点,c为character,s为string。</p>
<p><strong>4.打印历史查看过的变量:使用$number,而只使用$表示上一个变量。</strong>
</p>
<blockquote>
<p>(gdb) p tmp->left
<br>
$1 = (struct node *) 0x80496a8
<br>
(gdb) p *(tmp->left)
<br>
$2 = {val = 5, left = 0x0, right = 0x0}
<br>
(gdb) p *$1
<br>
$3 = {val = 5, left = 0x0, right = 0x0}</p>
<p>(gdb) p tmp->left
<br>
$1 = (struct node *) 0x80496a8
<br>
(gdb) p *$
<br>
$2 = {val = 5, left = 0x0, right = 0x0}</p>
</blockquote>
<p><strong>5.修改被调试程序运行时的变量值</strong>
:set x = 12。</p>
<p><strong>6.利用自定义变量方便调试:例如,</strong>
</p>
<pre style="background-color: #fbfbfb; width: 650px; overflow: auto; border: 1px solid #cecece; padding: 5px;"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 1: <span style="color: #0000ff;">int</span>
w[4] = {12,5,8,29};
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 2: main()
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 3: {
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 4: w[2] = 88;
</pre>
<pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 15px;"> 5: }</pre>
</pre>
<p>我们设置i,然后利用这个变量对这个数组进行遍历:</p>
<p>(gdb) set $i = 0
<br>
(gdb) p w[$i++]
<br>
$1=12
<br>
(gdb)
<br>
$2=5
<br>
(gdb)
<br>
$3=88
<br>
(gdb)
<br>
$4=29</p>
<p><strong>7.强制类型打印</strong>
</p>
<p>p {type}address:把address指定的内存解释为type类型(类似于强制转型,更加强)</p>
<p><strong>8.设置一些常见选项</strong>
</p>
<ul>
<li>1) set print array:打开数组显示,打开后当数组显示时,每个元素占一行,如果不打开的话,每个元素则以逗号分隔。默认关闭</li>
<li>2) set print elements num-of-elements:设置GDB打印数据时显示元素的个数,缺省为200,设为0表示不限制(unlimited)</li>
<li>3) set print null-stop:设置GDB打印字符数组的时候,遇到NULL时停止,缺省是关闭的 </li>
<li>4) set print pretty:设置GDB打印结构的时候,每行一个成员,并且有相应的缩进,缺省是关闭的</li>
<li>5) set print object:设置GDB打印多态类型的时候,打印实际的类型,缺省为关闭</li>
<li>6) set print static-members:设置GDB打印结构的时候,是否打印static成员,缺省是打开的</li>
<li>7) set print vtbl:GDB将用比较规整的格式来显示虚函数表,缺省是关闭的</li>
</ul>
<p>参考文献:
<br>
《Art of Debugging》
<br>
《Linux® Debugging and Performance Tuning: Tips and Techniques》</p>
<p>Author:gnuhpc
<br>
WebSite:blog.csdn.net/gnuhpc
</p>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值