以下是小编整理了Sco Unix下用dbxtra调试C程序Windows系统,本文共5篇,希望你喜欢,也可以帮助到您,欢迎分享!

篇1:Sco Unix下用dbxtra调试C程序Windows系统
Sco Unix 下用dbxtra调试C程序 人民银行合肥中心支行陆秉炜 在sco unix 下编程大多离不开C语言,即使是 数据库 应用也有很多是与c搭配使用的,例如 informixe sql /c就可以在c语言中嵌入sql语句,很多人认为在unix下写程序是件很痛苦的事情, 其中一个很重要
ScoUnix下用dbxtra调试C程序
人民银行合肥中心支行 陆秉炜
在scounix下编程大多离不开C语言,即使是数据库应用也有很多是与c搭配使用的,例如
informix esql/c 就可以在c语言中嵌入sql 语句。很多人认为在unix下写程序是件很痛苦的事情,
其中一个很重要原因是不知道在unix下怎样调试程序。其实在sco unix源码调试器是dbxtra或
dbXtra,linux下是gdb。它们类似turbo c的调试器,可以跟踪源码变量。在unix 下调试程序有
如下传统方法:
一、在要调试语句之前,输出要调试的变量,利用printf函数。
二、写日志文件,把结果输出到文件中避免屏幕混乱,利用fprintf()函数。
三、利用sco 内置调试器dbxtra或dbXtra。
dbxtra 适用字符界面,在sco unix的图形界面用dbXtra。(编按:请注意大小写)
以下是dbxtra基本命令:
c cont 在断点后继续执行
d delete 删除所设断点
h help 帮助
e edit 编辑源程序
n next 源程序区的内容向下翻一屏。
p print 显示变量
q quit 退出dbxtra
r run 运行程序,直到遇上设置的断点
rr rerun 再次运行
s step 单步运行
st stop 设置断点
j status 显示当前断点
t where 显示当前状态,列出所有设置的变量值
di display 开显示窗,用于查看变量
ud undisplay 删除显示窗的条目
f forward 源程序区的内容向上 翻一屏。
B backward 源程序区的内容向下 翻一屏。
Stopi stop inst 设置断点
tracei trace inst跟踪子程序
dbxtra [options] [objectfile ]
dbxtra 在启动时有个参数-Idir值得一提.我们在编写一个较大程序的时候,通常源程序和编译生成
的可执行文件都放在不同的目录中,这样便于管理,
默认dbxtra将在可执行文件所在的目录下找匹配c的源程序。
当我们启动时,指定-I参数,dbxtra就会到我们指定的目录下找匹配的c程序。 例如:
dbxtra -I“\work\c” program1
源程序在用clearcase/“ target=”_blank“ >cc编译时要带上-g 参数,这样是加上符号表等调试信息。只有这样编译过的文件,dbxtra才可以调试。调试信息使源代码和机器码关联。
下面这个C程序输出结果和我们的预想结果不一样,说明某些地方有错误。我们用调试器来
调试它:
程序一:
t.c
main()
{ int i=10 ,*p1;
float j=1.5,*p2;
p1=&
p2=&
p2=p1;
printf(”%d,%d\n“,*p1,*p2);
}
首先带上-g参数编译 cc -g -o t t.c
启动调试器 dbxtra t
屏幕显示:
1.main()
2.{ int i=10 ,*p1;
3. float j=1.5,*p2;
4. p1=&
5. p2=&
6. p2=p1;
7. printf(”%d,%d\n“,*p1,*p2);
8.}
C[browse] File:t.c Func.-
Readubg symbolic information
Type 'help' for help
(dbxtra)
(dbxtra)
设置断点:
(dbxtra)stop at 5
运行:
(dbxtra) run
程序自动在第5行停下。
这时我们可以看变量的值。
(dbxtra) print *p1
单步执行。
(dbxtra) step
程序将执行第5行源码,指针将移到第6行。
(dbxtra) print *p2
(dbxtra) step
程序执行了第6行源码后,将指针移到第7行。
(dbxtra) print *p1 , *p2
我们发现 在执行了第6行源码后,*p1,*p2的值就不对了,所以问题就出在第6行上。仔细检查后发现指针
p1指向整型,指针p2指向实型。它们之间的赋值要进行强制类型转换。这种错误在C程序中是很常见的。
有时我们在调试一些程序时,要在整个程序运行中时刻监视莫些变量的值,例如程序一中我们
要时刻了解*p1,*p2的值,除了在每一行程序执行完后,打print *p1,*p2外,还可以开一个显示窗口。
(dbxtra)display *p1,*p2
用undisplay 删掉不想要的变量。
有些程序运行时要带参数,mycat /etc/passwd 在调试时候
(dbxtra) run '/etc/passwd'
再运行时,无需再写一遍参数。
(dbxtra) rerun
在涉及到curses库编程或屏幕有大量的人机界面时,为了调试方便,我们可以把程序输出结果
重定向到个虚屏。
(dbxtra) run >/dev/tty03
当然要先把tty03 disable 掉。(disable tty03)
dbxtra还有很多高级的用法,有兴趣的读者可以参照dbxtra本身的help,进一步研究。
kelvin 回复于:-06-17 18:10:20多文件make出来的怎么调试,程序包含esql。
原文转自:www.ltesting.net
篇2:用 gdb 调试 GCC 程序Windows系统
用gdb调试G CC 程序 unix 下有一个叫gdb的GNU调试程序.gdb是一个用来调试C和C++程序的强力调试器.它使你能在程序运行时观察程序的内部结构和内存的使用情况.以下是gdb所提供的一些功能: 它使你能监视你程序中变量的值. 它使你能设置断点以使程序在指定的代码
用 gdb 调试 GCC程序
unix下有一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器. 它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的一些功能:
它使你能监视你程序中变量的值.
它使你能设置断点以使程序在指定的代码行上停止执行.
它使你能一行行的执行你的代码.
在命令行上键入 gdb 并按回车键就可以运行 gdb 了, 如果一切正常的话, gdb 将被启动并且你将在屏幕上看到类似的内容:
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type ”show copying“ to see the conditions.
There is absolutely no warranty for GDB; type ”show warranty“ for details.
GDB 4.14 (i486-slakware-linux), Copyright 1995 Free Software Foundation, Inc.
(gdb)
当你启动 gdb 后, 你能在命令行上指定很多的选项. 你也可以以下面的方式来运行 gdb :
gdb
当你用这种方式运行 gdb , 你能直接指定想要调试的程序. 这将告诉gdb 装入名为 fname 的可执行文件. 你也可以用 gdb 去检查一个因程序异常终止而产生的 core 文件, 或者与一个正在运行的程序相连. 你可以参考 gdb 指南页或在命令行上键入 gdb -h 得到一个有关这些选项的说明的简单列表.
为调试编译代码(Compiling Code for Debugging)
为了使 gdb 正常工作, 你必须使你的程序在编译时包含调试信息. 调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号. gdb 利用这些信息使源代码和机器码相关联.
在编译时用 -g 选项打开调试选项.
gdb 基本命令
gdb 支持很多的命令使你能实现不同的功能. 这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 表27.1列出了你在用 gdb 调试时会用到的一些命令. 想了解 gdb 的详细使用请参考 gdb 的指南页.
表 27.1. 基本 gdb 命令.
命 令 描 述
file 装入想要调试的可执行文件.
kill 终止正在调试的程序.
list 列出产生执行文件的源代码的一部分.
next 执行一行源代码但不进入函数内部.
step 执行一行源代码而且进入函数内部.
run 执行当前被调试的程序
quit 终止 gdb
watch 使你能监视一个变量的值而不管它何时被改变.
break 在代码里设置断点, 这将使程序执行到这里时被挂起.
make 使你能不退出 gdb 就可以重新产生可执行文件.
shell 使你能不离开 gdb 就执行UNIXshell 命令.
gdb 支持很多与 UNIX shell 程序一样的命令编辑特征. 你能象在 bash 或 tcsh里那样按 Tab 键让 gdb 帮你补齐一个唯一的命令, 如果不唯一的话 gdb 会列出所有匹配的命令. 你也能用光标键上下翻动历史命令.
gdb 应用举例
本节用一个实例教你一步步的用 gdb 调试程序. 被调试的程序相当的简单, 但它展示了 gdb 的典型应用.
下面列出了将被调试的程序. 这个程序被称为 greeting , 它显示一个简单的问候, 再用反序将它列出.
#include
main ()
{
char my_string[] = ”hello there“;
my_print (my_string);
my_print2 (my_string);
}
void my_print (char *string)
{
printf (”The string is %s\n“, string);
}
void my_print2 (char *string)
{
char *string2;
int size, i;
size = strlen (string);
string2 = (char *) malloc (size + 1);
for (i = 0; i < size; i++)
string2[size - i] = string[i];
string2[size+1] = `\0';
printf (”The string printed backward is %s\n“, string2);
}
用下面的命令编译它:
gcc -o test test.c
这个程序执行时显示如下结果:
The string is hello there
The string printed backward is
输出的第一行是正确的, 但第二行打印出的东西并不是我们所期望的. 我们所设想的输出应该是:
The string printed backward is ereht olleh
由于某些原因, my_print2 函数没有正常工作. 让我们用 gdb 看看问题究竟出在哪儿, 先键入如下命令:
gdb greeting
--------------------------------------------------------------------------------
注意: 记得在编译 greeting 程序时把调试选项打开.
--------------------------------------------------------------------------------
如果你在输入命令时忘了把要调试的程序作为参数传给 gdb , 你可以在 gdb 提示符下用 file 命令来载入它:
(gdb) file greeting
这个命令将载入 greeting 可执行文件就象你在 gdb 命令行里装入它一样.
这时你能用 gdb 的 run 命令来运行 greeting 了. 当它在 gdb 里被运行后结果大约会象这样:
(gdb) run
Starting program: /root/greeting
The string is hello there
The string printed backward is
Program exited with code 041
这个输出和在 gdb 外面运行的结果一样. 问题是, 为什么反序打印没有工作? 为了找出症结所在, 我们可以在 my_print2 函数的 for 语句后设一个断点, 具体的做法是在 gdb 提示符下键入 list 命令三次, 列出源代码:
(gdb) list
(gdb) list
(gdb) list
--------------------------------------------------------------------------------
技巧: 在 gdb 提示符下按回车健将重复上一个命令.
--------------------------------------------------------------------------------
第一次键入 list 命令的输出如下:
1 #include
2
3 main ()
4 {
5 char my_string[] = ”hello there“;
6
7 my_print (my_string);
8 my_print2 (my_string);
9 }
10
如果按下回车, gdb 将再执行一次 list 命令, 给出下列输出:
11 my_print (char *string)
12 {
13 printf (”The string is %s\n“, string);
14 }
15
16 my_print2 (char *string)
17 {
18 char *string2;
19 int size, i;
20
再按一次回车将列出 greeting 程序的剩余部分:
21 size = strlen (string);
22 string2 = (char *) malloc (size + 1);
23 for (i = 0; i < size; i++)
24 string2[size - i] = string[i];
25 string2[size+1] = `\0';
26 printf (”The string printed backward is %s\n“, string2);
27 }
根据列出的源程序, 你能看到要设断点的地方在第24行, 在 gdb 命令行提示符下键入如下命令设置断点:
(gdb) break 24
gdb 将作出如下的响应:
Breakpoint 1 at 0x139: file greeting.c, line 24
(gdb)
现在再键入 run 命令, 将产生如下的输出:
Starting program: /root/greeting
The string is hello there
Breakpoint 1, my_print2 (string = 0xbfffdc4 ”hello there“) at greeting.c :24
24 string2[size-i]=string[i]
你能通过设置一个观察 string2[size - i] 变量的值的观察点来看出错误是怎样产生的, 做法是键入:
(gdb) watch string2[size - i]
gdb 将作出如下回应:
Watchpoint 2: string2[size - i]
现在可以用 next 命令来一步步的执行 for 循环了:
(gdb) next
经过第一次循环后, gdb 告诉我们 string2[size - i] 的值是 `h`. gdb 用如下的显示来告诉你这个信息:
Watchpoint 2, string2[size - i]
Old value = 0 `\000'
New value = 104 `h'
my_print2(string = 0xbfffdc4 ”hello there“) at greeting.c:23
23 for (i=0; i
这个值正是期望的. 后来的数次循环的结果都是正确的. 当 i=10 时, 表达式 string2[size - i] 的值等于 `e`, size - i 的值等于 1, 最后一个字符已经拷到新串里了.
如果你再把循环执行下去, 你会看到已经没有值分配给 string2[0] 了, 而它是新串的第一个字符, 因为 malloc 函数在分配内存时把它们初始化为空(null)字符. 所以 string2 的第一个字符是空字符. 这解释了为什么在打印 string2 时没有任何输出了.
现在找出了问题出在哪里, 修正这个错误是很容易的. 你得把代码里写入 string2 的第一个字符的的偏移量改为 size - 1 而不是 size. 这是因为 string2 的大小为 12, 但起始偏移量是 0, 串内的字符从偏移量 0 到 偏移量 10, 偏移量 11 为空字符保留.
为了使代码正常工作有很多种修改办法. 一种是另设一个比串的实际大小小 1 的变量. 这是这种解决办法的代码:
#include
main ()
{
char my_string[] = ”hello there“;
my_print (my_string);
my_print2 (my_string);
}
my_print (char *string)
{
printf (”The string is %s\n“, string);
}
my_print2 (char *string)
{
char *string2;
int size, size2, i;
size = strlen (string);
size2 = size -1;
string2 = (char *) malloc (size + 1);
for (i = 0; i < size; i++)
string2[size2 - i] = string[i];
string2[size] = `\0';
printf (”The string printed backward is %s\n“, string2);
}
njlwm 回复于:2004-07-06 17:11:01#gdb
gdb: not found
#
????????????????????
原文转自:www.ltesting.net
篇3:UNIX开发系统程序调试例举Windows系统
来看看在哪些情况下需要对程序进行调试, 第一种情况(这是大多数用户都会碰到的),程序在运行过程中忽然跳了出来,屏幕上显示一个xxxx-coredumped消息, 然后Shell提示符就又显示出来了,其中xxxx表示出错原因。这种情况的出现一般是系统核心认为进程的执
来看看在哪些情况下需要对程序进行调试。
第一种情况(这是大多数用户都会碰到的),程序在运行过程中忽然跳了出来,屏幕上显示一个xxxx-core dumped消息,
然后Shell提示符就又显示出来了,其中xxxx表示出错原因。这种情况的出现一般是系统核心认为进程的执行出现了异常,
如进程试图去访问一块不允许它访问的存储区域(Memory Fault,Segmentation Fault);或者扫描某个无终止符的字符串
(Bus Error);或者浮点运算溢出或被0除(Arithmetic Exception),等等。此时操作系统会把进程当时的内存映象写到
当前目录下的一个名叫core的文件中。这种情况下我们可以使用sdb来检查此core文件,以决定出错的地点以及程序执行
的状态,如函数间的调用关系、变量的值,等等。
第二种情况,程序可能并没有什么异常行为,但就是怎么也得不到正确的输出结果。这时需要在该进程运行过程中对之进
行调试。这种情况下我们可以使用sdb逐条语句地跟踪程序的执行过程,并在执行过程中检查有关变量的值的变化情况。
上述两种情况并不是绝然分开的。实际上它们可以结合在一起使用。例如,当我们利用core文件对某个已终止的进程进行
调试时,可以在sdb中重新启动相应程序的运行,然后对语句的执行进行一些控制。这样我们就能够知道在出现异常之前哪
个程序到底是如何动作的。
为了使sdb能够很好地对程序进行调试,在编译程序时应指示编译程序和链接程序在目标代码中加入调试用的各种信息,如
程序中的变量名、函数名及其在源程序中的行号等。我们知道,使用-g选项可以完成这一点。如我们可以用如下命令编译
前一章给出的有毛病的程序代码:
$clearcase/” target=“_blank” >cc-o myprog myprog.c myfunc.c
myprog.c:
myfunc.c:
$ ls -l myprog
-rwx-xr-x 1 yxz users 4224 Sep 1 10:17 myprog
$ cc -g -o myprog myprog.c myfunc.c
myprog.c
myfunc.c
$ ls -l myprog
total 26
-rwxr-xr-x 1 yxz users 5404 Sep 1 10:21 myprog
$
这时我们会发现,新生成的myprog比不带-g 选项生成的myprog要大的多。故在程序调试完成之后应将可执行程序中的调试
用信息去掉。最简单的方法当然是使用不带-g 选项的cc命令重新编译一遍。另外UNIX系统提供了另外一个名为strip的工具,
使用此命令也可以将程序中的调试信息去掉。
现在我们可以试着运行一下那个有问题的程序myprog。在shell提示符下输入:
$ myprog 1 111
Arithmetic Exception -core dumped
$
我们看到,程序由于异常而推出了,并且在当前目录下将生成一个名为core 的文件。这个文件有时非常庞大。在文件系统
的维护中,有一条就是要定期找出各目录下的core 文件并将其删除掉。
发生此种情况时可以使用sdb来对之进行调试。输入:
$ sdb myprog
即可进入sdb调试程序。
sdb将接受三个参数:
待调试的可执行文件名;
待调试的core文件名,一般缺省是core;
由冒号分隔的一个目录表,sdb将在这些目录表中去查找有关的源文件。此目录表的缺省设置是当前目录
有时当前目录下的core文件可能并不是待调试的程序的core 文件,此时用这个core 文件进行调试就是不合适的了。为防止
这一点,可在命令行中指定第二个参数为减号(-),如下所示:
$ sdb myprog -
这里的“-”告诉sdb忽略当前目录下的core文件。
第三种情况,我们试用对活动过程(正在运行的进程)进行调试的情况。例如,假定某个程序正在后台运行,但我们注意到
该程序的某些部分执行起来非常慢,这时我们可以在不杀死这个进程的情况下对之进行调试:
$ sdb /proc/1111
这里1111为待调试进程的进程号,用户可以用PS命令得到。系统在/proc目录下用文件的形式保存了每一个活动进程的信息,
而文件名正好就是相应的进程号。
指定的进程将在执行时遇到第一个系统调用或调用sdb后收到某个软中断信号时暂停其运行,我们就可以在sdb中检查变量的值、
设置断点、恢复执行,等等。在退出sdb时,控制又返回程序,执行进程又从其原停止的地方继续执行。
第四种情况,一般情况下当被调试的活动进程在收到某个软中断信号时sdb会停止该进程。为了防止这一点,可以使用-s 选项。
例如:
$ sdb -s 14 myprog
将告诉sdb不要因为软中断信号14(闹钟报警信号)而使进程的执行停止。此时该信号被传给相应进程。在程序接收并处理多个
软中断信号的情况下,可以使用多个-s选项。
在sdb命令行中还有其他一些选项,对此我们不再一一列举,读者可以参考命令帮助。
在使用上述方法之一进入sdb之后,便可以进行在前一节中提到的各种操作,如显示或设置变量值、函数调用关系、控制语句的
执行等。下一节我们将详细讨论完成这些操作的方法。
sdb命令的使用
同我们前面介绍过的mail,ftp一类工具类似,sdb也是一个命令解释程序。也就是说,用户在sdb提示符(一个星号*)下输入sdb
能够识别的命令,sdb将根据被调试的程序的具体情况给出响应。
例如,在运行myprog出错,生成core文件之后进入sdb时,sdb将给出如下的响应:
$ sdb myprog
12: return ((100/atoi(ValueInput))? TESTOK:! TESTOK);
*
sdb给出来的实际上是程序出错所在的函数,在源程序文件中的行号以及出错那一行的语句。
在sdb的使用中要注意三个“当前”概念:
(1)当前文件 即当前将要被执行的语句所在的那个源程序文件
(2)当前函数 即当前将要被执行的语句所在的那个函数
(3)当前行 这个概念只有在编译时加入-g选项才会有,它指的是将要被执行的那条语句,
与当前行相应,有一个行号的概念。
它指的是每条语句在程序中位于第几行。注意行号是从文件头开始计算的,第一行的行号为1,空白行和注释也包括在内。
在用core文件进行调试时,当前行和当前函数分别被设成是程序出错时所执行的那条语句所在地行和函数(如同上面显示出来
的那样)。但如果在编译时未加-g选项,显示出来的将只有函数名和函数的地址了。
在对活动进程进行排错时,sdb将把当前函数和当前行分别设成是main函数和main()函数的第一个可执行的语句行。
不论是哪种情况,sdb都将显示出*提示符。在此提示符之下我们可以输入各种sdb命令,以控制程序的执行或观察变量的变化
情况,等等。在下面的几个小节中我们将分别详细讨论这些问题。
源程序的显示和搜索
程序出错一般来说不只是出错的那条语句本身造成的。事实上出现错误经常是前面或相关的代码执行了不正确的操作或少了某
些必要的处理。因此调试过程中经常要观察一下源程序中的语句,或者在程序中搜索某个符号出现在什么地方。其中字符串的
搜索功能同vi基本上是相同的,而文件的显示则同另外一个我们没有具体讨论的编辑器ed类似。下面我们将具体介绍这些命令。
1.源程序的显示
在用core进入sdb之后,在*提示符后输入w命令,该命令指示sdb显示源程序中的当前行为中心的前后10行的内容并保持当前行
不变:
* w
7:int
8: TestInput(char * ValueInput)
9: {while ( * ValueInput)
10: if (! isdigit( * ValueInput)) return (! TESTOK);
11: else ????ValueInput++;
12: return ((100/atoi(ValueInput))? TESTOK:! TESTOK);
13: }
*
我们看到,在进入sdb时,当前行是第12行,以该行为中心的10行内容正好就是上面所显示出来的。其他可以显示源程序语
句的sdb命令如下:
P 显示当前行
l 显示对应于当前指令的那条语句
Z 显示当前行开始的下面10条语句
Ctrl+D 显示当前行之后(不包括当前行)的第10条语句
n 显示第n条语句,这里n是一个数
注意这些命令显示出的是源程序语句还是汇编语句(后面我们将要介绍)取决于最近一次显示出的是什么。
2.改变当前行
在用户显示语句时,当前行也会相应地发生变化。例如,Z命令将使当前行向程序尾移动9行,而Ctrl+D则使当前行向后移
动10行。
在使用数字来显示某行语句时将使该行语句成为当前行。而在*提示符之后按一下回车,当前行将下移一行。例如,接着上面
的例子,输入:
* 8p
8: TEstInput(char * ValueInput)
* 回车
9: { while ( * ValueInput)}
*
这里8p实际上是两条命令的组合。它使当前行移至源文件的第八行,然后再显示出新的当前行。按回车键将使当前行后移一行。
3.改变当前源文件
在vi中我们可以用e命令对另外某个文件进行编辑。sdb也提供了e命令,可以用此命令来改变当前文件,如:
* e myprog.c
current file is now myprog.c
* 8p
8: main(int argc,char * argv[])
*
我们看到,当前文件改变之后,sdb将第一行设为是当前行。如果此文件的第一行是个函数,那么该函数便成为当前函数。
否则将临时出现没有当前函数的情况。
在上一节中,我们介绍过在命令行中可以指定源文件搜索目录名列表(缺省情况为当前目录)。如果某个文件不在此搜索
目录中,则可以用e命令将其加入:
* e Another SourceDir
这里Another SourceDir是一个目录名。如果要显示该目录下的某个文件,只需要输入:
* e FileName.c
当然直接使用:
* e Another SourceDir/FileName.c
也能达到同样的效果。
使用:
* e FunctionName
将使包含函数FunctionName的文件名成为当前文件,而当前函数不言而喻将成为FunctionName。当前行则理所当然的是该
函数的第一行。同一程序中函数名在各模块中的唯一性保证了这一点是能够成功的,但如果包含指定函数的文件不在当前
搜索目录列表中,则必须用e命令将其加入。
4.字符串的搜索
在vi中,我们可以在命令方式下使用“/“或者“?”命令,从当前位置向后或者向前搜索某个字符串,在sdb中也同样可
以完成这一点。使用这两个命令我们可以查找源程序中某个或某类符号的出现。之所以说某类,是因为我们可以用正规表
达式来指定待搜索的串(也即在搜索串中可以使用*,?,[,],-,^这类特殊字符)。
例如,为了查找myprog.c中argv出现在那些行上,可输入:
* /argv/
8: main(ini argc,char * argv[])
sdb将从当前行开始向文件尾搜索,到达文件尾之后又从文件头开始直至搜索到某个匹配的串或到达当前行为止。
与/相反,?命令将从当前行向文件头方向搜索,因此如果我们将上述/argv/换成:
* ? argv?
14: printf(“The %dth value' %s'\tis BAD! \n”,i,argv[i]);
*
所得的结果一般是不同的。
/或?命令之后的/或?并不是必须的。另外如果要在同一方向上继续搜索上次搜索过的串,只需要直接输入/或者?即可。
BOCAIX 回复于:-11-30 11:56:48十分感谢!!!
Red_Crow 回复于:2004-11-30 15:59:49:em02: !谢了。
原文转自:www.ltesting.net
篇4:一个SCO UNIX下端口扫描的C程序Windows系统
/*****************************************/ /*W.X.Y.-3编译成功*/ /*运行于SCO UNIX 系统*/ /*****************************************/ #includestdio.h #includesys/types.h #includesys/socket.h #includenetinet/in.h #includeerrno.h #include
/*****************************************/
/* W.X.Y.2001-3 编译成功 */
/* 运行于SCOUNIX系统 */
/*****************************************/
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int probeport = 0;
struct hostent *host;
int err, i, net;
int startport,endport;
struct sockaddr_in sa;
startport=1;
endport=700;
if(argc==3)
{
startport=endport=atoi(argv[2]);
}
if(argc==4)
{
startport=atoi(argv[2]);
endport=atoi(argv[3]);
}
for(i=startport;i
{
strncpy((char *)&sa,“”,sizeof sa);
sa.sin_family = AF_INET;
if(isdigit(*argv[1]))
sa.sin_addr.s_addr = inet_addr(argv [1]);
else if((host = gethostbyname(argv[1])) != 0)
strncpy((char *)&sa.sin_addr, (char *)host->h_addr,sizeof sa.sin_addr);
else
{
/*pherror(argv [1]); */
printf(“Usage: portscan address|hostname [start_port end_port]\n”);
printf(“ default port number from %d to %d\n”,startport,endport);
exit (2);
}
sa.sin_port = htons(i);
net = socket(AF_INET,SOCK_STREAM,0);
if(net<0)
{
perror(“\nsocket”);
exit(2);
}
err = connect(net,(struct sockaddr *) &sa,sizeof sa);
if(err<0)
{
/*
printf(“%s %-5d %s\r”,argv[1],i,strerror(errno));
*/
printf(“\r”);
fflush(stdout);
if(argc==3)
printf(“%s %-5d refused. \n”,argv[1],i);
}
else
{
printf(“%s %-5d aclearcase/” target=“_blank” >ccepted. \n“,argv[1],i);
if(shutdown(net,2)<0)
{
perror(”\nshutdown“);
exit(2);
}
}
close(net);
}
printf(”\r“);
fflush(stdout);
return(0);
}
/*程序结束*/
/*编译方法:*/
/* $cc -o portscan portscan.c -lnsl -lsocket*/
jysww 回复于:-02-19 22:43:15up!
yujf 回复于:2003-08-29 10:58:19怎么没有注释呀?可以提供点吗?
原文转自:www.ltesting.net
篇5:SCO Unix下开发游戏程序Windows系统
SCOUnix下开发游戏程序 中国银行河南修武支行王安定 作为成熟的操作系统,Unix在重要的行业中有很广泛的应用,而在实际应用中,却存在游戏软件少、游戏开发难度大等缺点。现在虽然推出了Unix下的X窗口,但因其应用的不广泛加上介绍功能的书籍少,使新手也很
SCO Unix下开发游戏程序
中国银行河南修武支行 王安定
作为成熟的操作系统,Unix在重要的行业中有很广泛的应用。而在实际应用中,却存在游戏软件少、游戏开发难度大等缺点。现在虽然推出了Unix下的 X窗口,但因其应用的不广泛加上介绍功能的书籍少,使新手也很难入手开发自己的游戏程序。下面以自己开发的一个小游戏来介绍在Unix中游戏开发的一些基本知识。
游戏名称:《Unix下的俄罗斯方块》
开发环境:SCO Unix System V/386 Release 3.2 后经少量改动在SCO OpenServer 5.0及多种Linux环境下编译通过
开发语言:Microsoft's C compiler version 6
开发方式:Unix字符方式下用Unix自带CURSES.H图形库开发
一、开发思路
1.单人游戏时:随机产生一个方块,用户使用键盘功能键操作方块,以合适的方式放入方块队列中。当某一行方块满时就消去这一行,显示用户所消行数及得分。机器中方块下落的速度会随得分的不同而改变。
2.联机对战:基本游戏思路同单人游戏,增加了对战功能。当多人进行对战时,如某玩家一次所消的方块行数大于二行,则把所消行数随机去掉一列后传给其他用户。在其他用户的界面上可以看到从游戏界面底部一下子增加了数行。
二、游戏的界面
在Unix下,游戏的界面是一个令人头痛的问题。在字符方式下,无法完成各种精美的图形。好在我们所开发的游戏对界面要求不太高。因此,对于新手来说,我们可以用Unix本身所带的CURSES.H库中几个简单的函数来完成界面设计。
1.下面介绍几种常用的CURSES.H函数:
initscr() 初始化屏幕(必须有)
clear()、wclear() 清屏
newwin() 开一个新窗口
box() 在窗口边画一个框
mvprintw(int x,int y,char *,...)类似于printf,不同之处是在窗口的 (x,y)位置显示信息
mvscanw(int,int,char *,...)在指定位置读信息
mvwaddstr() 在指定窗口的指定位置显示字符串
wstandout() 反相显示开始
wstandend() 反相显示结束
cbreak() 立即显示所接收到的字符
nocbreak() 接收到一个换行符后才显示所接收到的字符
echo() 显示所输入的字符
noecho() 不显示所输入的字符
delwin() 删除一个窗口
touchwin() 击活一个窗口
wrefresh() 刷新一个窗口
beep() 响铃
keypad() 功能键开关
wgetch() 在窗口中读一个字符输入
wmove() 在窗口中移动光标
endwin() 结束图形方式(必须有)
2.图形方式光标移动键定义如下:
KEY_DOWN 0402向下键
KEY_UP 0403 向上键
KEY_LEFT 0404向左键
KEY_RIGHT 0405向右键
三、随机方块的产生
在俄罗斯方块中,共有19种不同的方块类型,要随机产生不同的方块可以用以下两个函数来实现:
1.定义随机数发生器:根据时间函数的返回值不同而产生不同的随机数。
#define randomize() srand((unsigned)time(NULL))
2.定义随机数:该函数能产生介于0到num-1之间的所有数。
#define random(num) (rand()%num)
定义上面两函数后便可用下面的函数rand_block()产生一个随机数:
/* 程序功能:随机产生一个介于0-19之间的数;入口参数:无
返回值:flag */
int rand_block()
{
int flag;
randomize();
flag=rand(19);
return(flag);
}
四、游戏的控制-
---1.终端控制
Unix中终端的输入输出控制用的是ioctl()系统调用。原型如下:
#include
int ioctl(int fd,int request,struct termio *argu)
fd为文件描述字,与一台终端相对应;request 是一个命令,我们用到的命令有TCGETA和TCSETA两个,作用分别是将fd所对应的终端信息存入termio结构和将fd所对应的终端设定为termio所描述的形式。 argu是一个指向 termio 类型的指针。
程序中,对终端的控制主要是对中断键的处理和对输入模式的不同切换。对中断键的处理主要是用到termio指针中c_clearcase/” target=“_blank” >cc数组中的控制。下面的一段程序便可保存起当前终端信息,忽略中断键(置其值为255),然后重设当前终端。
struct termio *old_tbuf,tbuf;
ioctl(0,TCGETA,&old_tbuf); /* 取当前终端信息 */
tbuf=old_tbuf; /* 保存终端信息 */
tbuf.c_cc[VINTR]=255; /* DEL */
tbuf.c_cc[VQUIT]=255; /* CTRL-\ */
tbuf.c_cc[VERASE]=255; /* CTRL_h */
tbuf.c_cc[VKILL]=255; /* CTRL-u */
tbuf.c_cc[VEOL]=255; /* CTRL-d */
tbuf.c_cc[VSWTCH]=255; /* CTRL-z */
tbuf.c_cc[VSTOP]=255; /* CTRL-s */
tbuf.c_cc[VSTART]=255; /* CTRL-q */
ioctl(0,TCSETA,&tbuf);/* 设置当前终端 */
2.下落动画控制
在Unix系统中,有两种输入模式可供选择:一种是标准模式,一种是原始模式。在标准模式下,输入字符存储在输入队列的缓冲区中,直到读入换行符或是EOT(^-d)字符后才将所有数据一次输出;在原始模式下,字符一键入就立即输出,没有缓冲区。系统默认的是标准模式,但在游戏中,我们要不断在两种模式间切换,完成切换要用到tbuf.c_lflag[ICANON]来完成,如果设为ON,则默认为标准输入模式,否则为原始模式。
在游戏中,我们要求每一个方块在产生后,便能自动地下落。实现这个动画效果,要用到原始模式下的两个重要标志:VMIN和 VTIME,它们分别表示read系统调用返回前所需读取的最少字数和最长时间,
要控制方块自动下落,可用下面两句:
tbuf.c_cc[VMIN]=0;
tbuf.c_cc[VTIME]=1;
ioctl(0,TCSETA,&tbuf);
功能:read在收到一个字符或未收到字符但定时一秒时返回
3.速度控制
在俄罗斯方块中,游戏的可玩性还在于速度在不断的变化中。在这里,我们就要用到间隔化技术。所谓间隔化技术,就是在指定了开始位置和结束位置的情况下,确定游戏间隔步骤过程的技术。我们可以用一个空循环来实现方块因得分不同而使每一次下落的速度不同。定义速度常数 SPEED为十万(可根据机器速度不同自行定义),然后根据不同的行分而改变循环次数,如下边所写(score为用户当前得分):
if(score<10000) for(i=0;i else for(i=0;i五、游戏操作的实现 在游戏中,对方块的操作主要是由几个光标功能键来控制,功能定义如下:
1、↑ 翻转
2、↓ 速降
3、← 左移
4、→ 右移 5、Esc结束 6、c 刷屏
7、p 暂停
由于在图形方式下不能完成对方块的各种操作,这就使我们要找到合适的函数来定义各功能键。在Unix中,↑↓ ← →各键的引导字符是27,对游戏操作的实现也就是改变方块显示位置及显示不同方块类型的转换。当然还可以定义一些秘键:减速、增速、使对手增行、清空自己所有行等。
六、游戏的记录
1.记录结构的定义:
struct user_data
{
char name[8]; /* 用户姓名 */
int score; /* 用户最高得分 */
int line; /* 最高分时所消除方块行数 */
}
2.记录文件的几种操作:
在程序中要用到记录文件来存放用户记录,本游戏中记录文件名为user.dat,以下是几种文件的常用操作。在操作前要先定义一个FILE类型的指针 (FILE *fp):
fopen() 打开文件
fscanf() 从文件中读数据
access() 检测文件存在否及文件属性
creat() 建立新文件
fseek() 文件定位
fprintf() 写数据到文件中
fclose() 关闭文件
用下面的一段程序便可测试用户记录文件存在否。如不存在,则建立新的文件,并写一个空的入门成绩到用户记录文件中。游戏中你可用这几个函数来往记录文件中追加新的记录或改写记录。
if(access(“user.dat“,00)) /* 检测有无用户记录文件 */
{
creat(“user.dat”,0644); /* 如无文件则建立新的文件 */
fp=fopen(“user.dat“,“r+”); /* 写入一个空记录 */
fprintf(fp,“入门成绩 3000 20\n“);fclose(fp);
七、联机对战的实现
联机对战的主要思路是在各个不同用户间传递信息。在Unix 下,我们可以用消息队列来进行数据的传递。消息队列能将格式化的数据送往任意的进程,所用到的有关系统调用如下。
1.建构一个新的消息队列或取得一个现存的消息队列的标识符:
#include “sys/types.h”
#include “sys/ipc.h“
#include “sys/msg.h”
int msgget(key_t key,int flags)
key是指消息队列的名字,它的值若是IPC_PRIVATE(值为零),指该消息队列为该进程专用,否则表示为一个以上的进程所共用。
flags用于表示消息队列的存取权限。
2.取得或修改已存在的消息队列的属性:
int msgctl(int msgid,int cmd,struct msqid_ds *mbuf)
msgid是消息队列的标识符。
cmd为符号常数: IPC_STAT(拷贝消息队列到MBUF所指向的地址)、IPC_SET(设定消息队列的存取权限)、IPC_RMID(删除消息队列)。
3.发送和接收消息:
int msgsnd(int msgid,const void *msgp,size_t msgsz,int msgflg)
int msgrcv(int msgid,void *msgp,size_t msgsz,long msgtyp,int msgflg)
msgid:消息队列的标识符。
msgp:消息缓冲区,暂时存储发送与接收的消息。
msgsz:消息的大小。
msgtyp:消息的类型。
msgflg:用来指明核心程序在队列没有数据的状况下,所应采取的行动。
八、游戏中的各种标志位
最重要的标志位是位置方块标志:定义一个二维数组,对应于游戏中方块的区域大小。如play[25][80],然后根据该标志为0或1来判断该位置有无方块,其他标志都是根据这个标志来工作的。所用到的标志还有游戏左右界标志、消行标志、增行标志(联机对战中)、能否移动标志、游戏结束标志等。
九、其他功能
游戏主体内容建立后,还有一些功能需要用户自己来完成。如清除上次显示方块、显示下一方块提示信息、无敌作弊法、记录排序、游戏速度的精确计算、增删行函数、速降函数、方块变换等,还需要进一步完善才成为完整的程序。
附例程:从标准输入读字符,如为光标移动键返回该键值,否则返回该字符值。
int mygetch()
{
int i;
char c;
struct termio *old_tbuf,tbuf;
ioctl(0,TCGETA,&old_tbuf);/* 取当前终端信息 */
tbuf=old_tbuf;
tbuf.c_lflag&=~ICANON; /* 设为原始模式 */
tbuf.c_cc[VNUM]=1;/* 设最少输入一个字符 */
tbuf.c_cc[VTIME]=0;/* 等待时间为0 */
ioctl(0,TCSETA,&tbuf);
i=read(0,&c,1);
if(c==27){/* 如为27则为光标键前导码 */
read(0,&c,1);read(0,&c,1);
switch(c){
case ‘A':return(56);break;/* UP */
case ‘B':return(50);break;/* DOWN */
case ‘C':return(54);break;/* RIGHT */
case ‘D':return(52);break;/* LEFT */
case 27:return(27);break;/* ESC */
}
ioctl(0,TCSETA,&old_tbuf);
return(c);
}
【发表回复】【查看CU论坛原帖】【添加到收藏夹】【关闭】
原文转自:www.ltesting.net
★用VOLMANAGE可以在线扩展文件系统吗Windows系统
文档为doc格式