**dc**（desk calculator：桌面计算器）是采用逆波兰表示法的跨平台计算器，它支持任意精度算术。它是Robert Morris（英语：）在贝尔实验室期间书写的，作为最老的Unix实用工具，先于C语言的发明。像那个年代的其他实用工具一样，它有着一组强力的特征和简洁的语法。传统上，采用中缀表示法的bc计算器程序是在dc之上实现的。

历史
--

dc是幸存的最老的Unix语言。在贝尔实验室收到第一台PDP-11的时候，用B语言写成的dc是在这个新机器上运行的第一个语言，甚至在汇编器之前。

基本操作
----

在dc中要做4和5的乘法：

```
$ dc
4 5 \*
p
20
q

```

这可转译为"把4和5压入栈顶，通过乘法算符，从栈中弹出两个元素，将二者相乘并把结果压回栈顶"。接着使用`p`命令打印栈顶的元素。使用`q`命令退出此次调用的dc实例。注意数值相互间必须以空白分隔，但某些算符可以不必如此。
还可以用如下命令得到这个结果：

```
$ dc -e '4 5 \* p'
20
$ echo "4 5 \* p" |dc
20
$ dc -
4 5\*pq
20
$ cat <<EOF > cal.txt
4 5 \*
p 
EOF
$ dc cal.txt
20

```

使用命令`k`来变更算术精度，它设置算术运算的小数位数。因为缺省精度是`0`，例如：

```
$ dc -e "2 3 / p"
0

```

通过使用命令`k`调整精度，可以产生任意数目的小数数位，例如：

```
$ dc -e "5 k 2 3 / p"
.66666

```

dc有科学计算器的基本运算功能，比如求{\displaystyle {\sqrt {12+(-3)^{4} \over 11}}-22}的值：

```
$ dc -e "2k 12 \_3 4 ^ + 11 / v 22 - p"
-19.10

```

其中，`_`用于输入负数，`^`计算幂，`v`计算平方根。

使用`d`命令复制栈顶元素。使用`r`命令对栈顶和仅次栈顶的两个元素进行对换。使用`z`命令压入当前栈深度，即执行`z`命令前栈中元素的数目。

输入/输出
-----

使用`?`命令，从stdin读取一行并执行它。这允许从宏中向用户要求输入，故而此输入必须是语法上正确的，并且这有潜在的安全问题，因为dc的`!`命令可以执行任意系统命令。

前面提及过，`p`命令打印栈顶元素，带有随后的一个换行。`n`命令弹出栈顶元素并输出它，没有尾随换行。`f`命令打印整个栈，一项一行。

dc还支持控制输入和输出的基数。`i`命令弹出栈顶元素并将它用作输入基数。十六进制数字必须大写以避免和dc命令冲突，输入基数必须在2和16之间，输出基数必须大于等于2。`o`命令设置输出基数，要记住输入基数将影响对后面的所有数值的分析，所以通常建议先设置输出基数。例如将二进制转换成十六进制：

```
$ echo 16o2i 11011110101011011011111011101111p | dc
DEADBEEF

```

要读取设置的这些数值，`K`、`I`和`O`命令将压入当前精度、输入基数和输出基数到栈顶。

语言特征
----

除了上述的基本算术和栈操作，dc包括了对宏、条件和存储结果用于以后检索的支持。

### 寄存器

寄存器在dc中是有着单一字符名字的存贮位置，它可以通过命令来存储和检索，它是宏和条件的底层机制：`sc`弹出栈顶元素并将它存储入寄存器`c`，而`lc`将寄存器`c`的值压入栈顶。例如：

```
 3 sc 4 lc * p
```

寄存器还被当作次要栈，可以使用`S`和`L`命令在它们和主要栈之间压入和弹出数值。存储栈顶元素到寄存器中并把这个元素留在栈顶，需要联合使用`ds`命令。

### 字符串

字符串是包围在`[`和`]`之中的字符，可以被压入栈顶和存入寄存器。使用`x`命令从栈顶弹出字符串并执行它，使用`P`命令从栈顶弹出并打印字符串，无尾随换行。`a`命令可以把数值的低位字节转换成ASCII字符，或者在栈顶是字符串时把它替换为这个字符串的第一个字符。此外没有方法去建造字符串或进行字符串操纵。

`#`字符开始一个注释直到此行结束。

### 宏

通过允许寄存器和栈项目像数值一样存储字符串，从而实现了宏。一个字符串可以被打印，也可以被执行，就是说作为dc命令的序列而传递。例如可以把一个宏"加1并接着乘以2"存储到一个寄存器`m`中：

```
 [1 + 2 *] sm
```

通过使用`x`命令弹出栈顶的字符串并执行之，如下这样使用存储的宏：

```
 3 lm x p
```

`Q`命令从栈顶弹出一个值作为退出宏的层数，比如`2Q`命令退出2层宏，它永不导致退出dc。`q`命令退出2层宏，如果宏少于2层则退出dc。

### 条件

最后提供了有条件执行宏的机制。命令`=r`将从栈顶弹出两个值，如果二者相等，则执行存储在寄存器`r`中的宏。如下命令序列将在原栈顶元素等于5的条件下打印字符串`equal`。

```
[[equal]p] sm d 5 =m
```

这里使用了`d`命令保留原栈顶元素。其他条件有`>`、`!>`、`<`、`!<`、`!=`，如果栈顶元素分别大于、不大于（小于等于）、小于、不小于（大于等于）、不等于仅次于栈顶的元素，则执行指定宏。

### 迭代

通过定义有条件的调用自身的递归宏，迭代也是可行的。一个简单的对栈顶元素的阶乘过程：

```
 # F(x): return x!
 # if x-1 > 1
 #    return x * F(x-1)
 # otherwise
 #    return x
```

可实现为：

```
 [d1-d1<F*]dsFxp
```

这里宏中的第一个`d`命令相当于分配了一个局部变量。

例子
--

Unix V7手册页举出的编程实例为打印阶乘n!的前10个值：

```
$ dc -e "[la1+dsa\*pla10>y]sy 0sa1 lyx"
1
2
6
24
120
720
5040
40320
362880
3628800

```

这个程序实现了For循环，将作为循环体的宏`[la1+dsa*pla10>y]`存储在寄存器`y`中；把寄存器`a`作为循环计数器，设其初始值为`0`，将0!的值`1`压入栈顶；从寄存器`y`中取出宏并执行之。宏中的`la1+dsa`将计数器`a`的数值加`1`，并将这个值留在栈顶；随后`*p`从栈中弹出两个元素进行乘法并把结果压入栈中，打印这个结果；随后`la10>y`将计数器`a`的数值和数值`10`压入栈中，判断位于栈顶的`10`是否大于计数器的数值，即计数器的数值是否小于`10`，弹出二者并在判断成立的条件下再次执行存储在寄存器`y`中的宏。计数器`a`的数值从`0`增加到`10`，宏一共被执行了`10`次。

参见
--

* bc
* 计算器输入方法（英语：）
* 堆栈机器

引用
--

1. ↑  `dc(1)`: an arbitrary precision calculator – Linux用户命令（User Commands）手册页
2. 1 2  Brian Kernighan and Ken Thompson.. YouTube. 事件发生在 29m45s.  [September 3, 2019]. （原始内容存档于2022-02-01）.
3. ↑ .  [2020-09-25]. （原始内容存档于2019-09-24）.
4. ↑  Ritchie, Dennis M.. Sep 1979  [2019-05-31]. （原始内容存档于2010-05-06）.
5. ↑  McIlroy, M. D.  (PDF) (技术报告). CSTR. Bell Labs. 1987  [2019-05-31]. 139. （原始内容存档 (PDF)于2019-11-30）.

外部链接
----

* 软件包dc（页面存档备份，存于）在Debian GNU/Linux仓库中
* bc的原生Windows移植包括了dc
* 嵌入到网页中的dc（页面存档备份，存于）
* The unix dc(1) command, this is the esoteric language that "made it big". （页面存档备份，存于）

   

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
Unix命令行程序和shell内建命令 |
| --- |
|  |
| 文件系統 | 
* cat
* cd
* chmod
* chown
* chgrp
* cksum
* cmp
* cp
* dd
* du
* df
* file
* fsck
* fuser
* ln
* ls
* mkdir
* mount
* mv
* pax（英语：）
* pwd
* rm
* rmdir
* size
* split
* stat
* tee
* touch
* type（英语：）
* umask（英语：）

 |
|  |
| 程序 | 
* at
* bg
* chroot
* cron
* fg
* kill
* killall（英语：）
* nice
* pgrep
* pkill（英语：）
* ps
* pstree（英语：）
* time
* top

 |
|  |
| 用户环境 | 
* clear
* env
* exit
* history（英语：）
* id
* logname
* mesg（英语：）
* passwd
* su
* sudo
* uptime
* talk（英语：）
* tput（英语：）
* uname
* w
* wall（英语：）
* who
* whoami
* write（英语：）

 |
|  |
| 文本编辑 | 
* awk
* banner（英语：）
* basename
* comm（英语：）
* csplit（英语：）
* cut
* diff
* dirname
* ed
* ex
* fmt（英语：）
* fold（英语：）
* head（英语：）
* iconv
* join（英语：）
* less
* more
* nl（英语：）
* paste（英语：）
* sed
* sort（英语：）
* spell（英语：）
* strings（英语：）
* tail
* tr
* uniq（英语：）
* vi
* wc
* xargs

 |
|  |
| 壳层内建 | 
* alias
* echo
* printf格式字符串
* test（英语：）
* unset
* wait

 |
|  |
| 网络 | 
* dig
* host
* ifconfig
* inetd（英语：）
* netcat
* netstat
* nslookup
* ping
* rdate（英语：）
* rlogin（英语：）
* route
* ssh
* traceroute

 |
|  |
| 查找 | 
* find
* grep
* locate
* whatis（英语：）
* whereis

 |
|  |
| 文档 | 
* apropos（英语：）
* help（英语：）
* man

 |
|  |
| 软件开发 | 
* ar
* ctags
* lex
* make
* nm
* strip
* yacc

 |
|  |
| 杂项 | 
* bc
* cal
* dc
* expr
* lp（英语：）
* lpr
* sleep
* true和false
* yes

 |
|  |
| Unix实用程序列表 |

 |