crossz

Archive for the ‘C/C++’ Category

Matlab: Mex example in C way

In C/C++, matlab on August 20, 2009 at 1:13 am

There is a yprime.c for mex in Matlab. Here I translate to C, in order to understand mex better.

#include <math.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

static void yprime(
double* yp,
double* y
)
{
double r1,r2;

double mu = 1/82.45;
double mus = 1 – 1/82.45;

r1 = sqrt((y[0]+mu)*(y[0]+mu) + y[2]*y[2]);
r2 = sqrt((y[0]-mus)*(y[0]-mus) + y[2]*y[2]);

yp[0] = y[1];
yp[1] = 2*y[3]+y[0]-mus*(y[0]+mu)/(r1*r1*r1)-mu*(y[0]-mus)/(r2*r2*r2);
yp[2] = y[3];
yp[3] = -2*y[1] + y[2] – mus*y[2]/(r1*r1*r1) – mu*y[2]/(r2*r2*r2);
return;
}

int main(){
double yo[4];
double yi[4] = {100, 2, 3, 4};

yprime(yo, yi);
printf(“print out %f”,yo[0]);

// some conversion practice
double a = yi[0];
char t1[7],t2[8],t3[8];

*t1= (char) a;
strcpy(t2,t1);

printf(strcat(t1, t2));

gcvt(a,7,t3);
puts(t3);

// i = sprintf(str, “%d”, 15); //for interger to string

return 0;
}

HOWTO: compile objective-c using gcc in Linux

In C/C++ on August 16, 2009 at 5:24 pm

to compile these examples of objective-c (install libobjc first) from objective-c on wikipedia.org

1) traditional:
gcc -c XX.m XXX.m -Wno-import
gcc -o prog XX.o XXX.o -lobjc -Wno-import

2) gcc *.m -lojbc -Wno-import

Note:
-Wno-import is because the maintainer of gcc doesn’t like ‘import’;

-lobjc: -l(library) -L(libaray directory) -lobjc(for GNU objective-c libraray)

For those examples using GNUstep, most of the header files need to be changed from ‘ #import ‘ to ‘#import ‘ to suit the GNU objective-c library.

More details: http://www.cs.indiana.edu/classes/c304/oop-intro.html

Review: pointer, reference in c++

In Blogged, C/C++ on December 1, 2008 at 12:07 am
A Reference Guide
Last updated Jan 1, 2004.from: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=166

Unlike most other programming languages, C++ offers an unusual diversity of argument passing mechanisms: pass by value, pass by address, and pass by reference. Additional non-standard argument-passing mechanisms are also supported by certain compilers, such as passing arguments on a register. Today I will explain the semantics of the three standard argument passing mechanisms, and focus on reference variables.

A bit of History
Most high level programming languages offer only a single argument passing mechanism. In Pascal and Ada, for example, arguments are passed by reference and that’s it. In Java, objects are passed by reference, whereas fundamental types such as int and boolean are passed by value.

The crucial point, however, is that programmers cannot intervene or control the actual argument passing mechanism that the language applies. C is different in this regard. Built on the foundations of BCPL and B, which were really nothing more than high-level assembly languages, it offered two argument passing mechanisms: pass-by-value and pass by address. Oddly enough, it didn’t offer the more common notion of pass by reference.

Pass by Value
Pass by Value is the default argument passing mechanism of both C and C++. When a caller passes by value an argument to a function (known as the callee), the latter gets a copy of the original argument. This copy remains in scope until the function returns and is destroyed immediately afterwards. Consequently, a function that takes value-arguments cannot change them, because the changes will apply only to local copies, not the actual caller’s variables. For example:

void negate(int n) //buggy version
{
n=-n;//affects a local copy of n
}
void func()
{
int m=10;
negate(m);//doesn’t change the value of m
std::cout<<m<<std::endl; //diplay: 10
}
When negate() is called, C++ creates a fresh copy of m on its stack. negate() then modifies this private copy, which is destroyed immediately when it returns. The original variable m remains intact, though. Consequently, the cout expression displays 10 rather than -10. If you want the callee to modify its arguments, you must override the default passing mechanism.

Pass by Address
In C, the only way to achieve this is by passing the argument’s address to the callee. This passing mechanism is traditionally called pass by address.

In the literature, this often called pass by reference too, although it’s is a misnomer — C++ uses this term to denote a radically different passing mechanism. For example,

void negate(int * pn)
{
*n=-*n;
Similarly, the caller must also be adjusted:

void func()
{
int m=10;
negate(&m);//pass m’s address<
std::cout<<m<<std::endl; //display: -10
}
Pass by Reference
This is all well and good. The problem with this technique is that it’s tedious and error-prone. My impression is statistically, most C/C++ function calls don’t use pass by value so forcing programmers to override the default passing mechanism using the &, * and -> operators is an example of a bad language design choice. C++ creators were aware of this. They introduced a new type of argument passing, namely pass by reference. The addition of reference variables and arguments to C++ was only a means of fixing an historical accident made in C about a decade earlier rather than a genuine innovation. However, the introduction of references did affect fundamental programming idioms in C++.

Most textbooks will tell you that a reference is “an alias for an existing object.” For example,

int m=0;
int &ref=m;
The reference ref serves as an alias for the variable m. Thus, any change applied to m is reflected in ref and vice versa:

++m;
std::cout<<ref<<std::endl;// output 1
++ref; //increment m
std::cout<<m<<std::endl;// output 2
In other words, ref and m behave as distinct names of the same object. In fact, you may define an infinite number of references to the same object:

int & ref2=ref;
int & ref3=m;
//..and so on
Here ref2 and ref3 are aliases of m, too. Notice that there’s no such thing as a “reference to a reference;” the variable ref2 is an alias of m, not ref.

Usage
In most cases, references are used as a means of passing arguments to a function by reference. The nice thing about references is that they function as pointers from a compiler’s point of view, although syntactically they behave like ordinary variables. They enable a callee to alter its arguments without forcing programmers to use the unwieldy *, & and -> notation:

void negate(int & n)
{
>n=-n;//modifies caller’s argument
}
void func()
{
int m=10;
negate(m);//pass by reference
std::cout<<m<<std::endl; //diplay: -10
}
Advantages of Pass by Reference
Passing by reference combines the benefits of passing by address and passing by value. It’s efficient, just like passing by address because the callee doesn’t get a copy of the original value but rather an alias thereof (under the hood, all compilers substitute reference arguments with ordinary pointers). In addition, it offers a more intuitive syntax and requires less keystrokes from the programmer. Finally, references are usually safer than ordinary pointers because they are always bound to a valid object — C++ doesn’t have null references so you don’t need to check whether a reference argument is null before examining its value or assigning to it.

Passing objects by reference is usually more efficient than passing them by value because no large chunks of memory are being copied and constructor and destructor calls are performed in this case. However, this argument passing mechanism enables a function to modify its argument even if it’s not supposed to. To avert this, declare all read-only parameters as const and pass them by reference. This way, the callee will not be able to modify them:

void display(const Shape & s)
{
s.draw();
}
Summary
The introduction of references to C++ initially caused a bit of confusion, especially among ex-C programmers who weren’t sure which passing mechanism to use when (and in those days, virtually all C++ programmers were former C programmers). Even illustrious gurus offered to use the following dichotomy: when a function modifies its arguments, pass them by address and when it doesn’t, pass them as references to const.

Today, using bare pointers is a thing of the past. In most cases, C++ offers superior alternatives that are both safer and cleaner. Similarly, when you decide how to pass arguments to a function, use references by default (except when you truly need to pass them by value) and avoid passing by address, unless there’s a compelling reason to do so. If the function in question shouldn’t modify its arguments, they should be declared const and passed by reference; the lack of the const qualifier indicates that the function is allowed to modify an argument. When should you pass arguments by address? Only when the function deals with real pointers. For instance, a function that allocates raw storage, or when a null pointer is a valid option. Otherwise, use references.

efficiency of python calling c exetuable

In C/C++, python on November 26, 2008 at 6:28 pm

python 可以用popen调用一个c语言的可执行程序。但是效率如何呢?

1)一个c程序: 调用一个循环求和从1到1000的function 10000次。
之所以要调用循环求和从1到1000,是因为这个function要声称另外的一个可执行文件供python调用,所以外部框架c和python都差不多,就是要往复调用这个function,以得出python与c的沟通效率。
#######################
/*
* File: newmain.c
* Author: cross
*
* Created on 26 November 2008, 16:08
*/

#include <stdio.h>
#include <stdlib.h>

struct timeb {
time_t time;
unsigned short millitm;
short timezone;
short dstflag;
};
//ftime returns a struct with above structure.

int internal_loop(){
int ii=0,ss=0;
while (ii<1000)
{
ss+=ii;
ii++;
}
printf(“%i\n”,ss);
return ss;
}

int main(int argc, char** argv) {

struct timeb t1,t2;
double i=0,s=0;

ftime(&t1);

int repeat = 10000;
while(i<repeat){
s+=internal_loop();
i++;
}

ftime(&t2);
printf(“%.1f\n”,s);

printf(“time = %ld.%d\n”,t1.time,t1.millitm);
printf(“time = %ld.%d\n”,t2.time,t2.millitm);

return (EXIT_SUCCESS);
}

##################

2)以上的internal_loop function被单独生成一个c的可执行文件b.o,供python调用。以下是python代码。
##################

import datetime
import os

t1= datetime.datetime.now()

j=0
k=1000
for i in range(1,k):
printed=os.popen('/home/cross/NetBeansProjects/Application_2/b.o')
printed.readlines()
printed.close()

print # to print a new line

t2= datetime.datetime.now()

tstr=[(t2-t1).seconds,(t2-t1).microseconds] # the attributes of timedelta class: senconds and microseconds, from http://docs.python.org/lib/datetime-timedelta.html#l2h-602
print 'Repeated sum of 1-1000 ',k,' times : '
print tstr

###############

3) 只用python单独完成和1)一样的过程,python代码如下:
########################
import datetime

t1= datetime.datetime.now()

k=10000
for i in range(1,k):
    j=0
    for ii in range(1,1000):
        j=j+ii
    print j

print # to print a new line

t2= datetime.datetime.now()

tstr=[(t2-t1).seconds,(t2-t1).microseconds] # the attributes of timedelta class: senconds and microseconds, from http://docs.python.org/lib/datetime-timedelta.html#l2h-602
print ‘Repeated sum of 1-1000 ‘,k,’ times : ‘
print tstr

#####################

总结
如果成功运行以上两个程序,同样是运行10000次,1)耗时274毫秒;2)20秒。
可见python与其他程序通过popen这种字符沟通的效率是比较低的。以上,1)是同一个程序调用一个子函数,速度当然是最理想的。而2)是通过console的字符交换得以沟通,这种效率当然低,甚至这还远不如主程序和子程序的沟通效率。

通过1)和3)的比较,可以很容易看出来python的语法简单,但是python比c慢也是事实,3)用时3.8秒。

HOWTO: Calling c (or other programs) from python

In C/C++, howto, python on November 26, 2008 at 3:29 pm

Calling c (or other programs) from python

1. swig (to generate a python extention from c)
2. dl, python object (to call c shared library)
3. os.popen() (to call other exetuable programs)

In this example, I will use the 3rd method.

1) c program.
This is an example from netbeans, it can print all the arguments, argv[0] is the program name.
# args.c ###################################
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char**argv) {
int i;
// Prints arguments
printf("Arguments:\n");
for (i = 0; i < argc; i++) {
printf("%i: %s\n", i, argv[i]);
}

return 0;
}
#############################
compile it:
####
gcc args.c -o a.out
####

2) python script

# in python script ################
import os
printed = os.popen(‘./a.o hello world’)
>>> printed.readline()
‘Arguments:\n’
>>> printed.readline()
‘0: ./a.o\n’
>>> printed.readline()
‘1: hello\n’
>>> printed.readline()
‘2: world\n’
>>> printed.readline()

##################################
Here printed is an python array object, all the methods for array are available.

C语言-指针; 2008温习

In C/C++ on November 21, 2008 at 7:52 pm

指针变量在定义中允许带初始化项。如:
int i, *ip=&i;
注意, 这里是用&i 对ip初始化, 而不是对*ip初始化。和一般变量一样,对于外部或静态指针变量在定义中若不带初始化项, 指针变量被初始化为NULL, 它的值为0。 Turbo C中规定, 当指针值为零时, 指针不指向任何有效数据, 有时也称指针为空指针。
int i=200, x;
int *ip;
我们定义了两个整型变量i,x,还定义了一个指向整型数的指针变量ip。i,x中可存放整数,而ip中只能存放整型变量的地址。我们可以把i的地址赋给ip:
ip=&i;
此时指针变量ip指向整型变量i.

字符指针
char *cp;
于是可用:
cp=a string;
使cp指向字符串常量中的第0号字符a, 如图所示。
CP—– | a | | s | t | r | i | n | g | |

以后我们可通过cp来访问这一存贮区域, 如*cp或cp[0]就是字符a,而cp[i]或*(cp+i)就相当于字符串的第i号字符,但企图通过指针来修改字符串常量的行为是没有意义的。
而char *Names[]表示指向字符的指针数组。

Turbo C中,数组名是数组的第0号元素的地址,因此下面两个语句是等价的
p=&a[0];
p=a;
根据地址运算规则,a+1为a[1]的地址,a+i就为a[i]的地址。
下面我们用指针给出数组元素的地址和内容的几种表示形式:
(1). p+i和a+i均表示a[i]的地址, 或者讲,它们均指向数组第i号元素, 即指向a[i]。
(2). *(p+i)和*(a+i)都表示p+i和a+i所指对象的内容,即为a[i]。
(3). 指向数组元素的指针, 也可以表示成数组的形式,也就是说,它允许指针变量带下标, 如p[i]与*(p+i)等价。
对于二维数组:
我们把a[0],a[1],a[2]看成是一维数组名,可以认为它们分别代表它们所对应的数组的首地址,也就是讲,a[0]代表第 0 行中第 0 列元素的地址,即&a[0][0], a[1]是第1行中第0列元素的地址,即&a[1][0],根据地址运算规则,a[0]+1即代表第0 行第1列元素的地址,即&a[0][1],一般而言,a[i]+j即代表第i行第j列元素的地址, 即&a[i][j]。
另外,在二维数组中,我们还可用指针的形式来表示各元素的地址。如前所述,a[0]与*(a+0)等价,a[1]与*(a+1)等价,因此a[i]+j就与*(a+i)+j等价,它表示数组元素a[i][j]的地址。
因此,二维数组元素a[i][j]可表示成*(a[i]+j)或*(*(a+i)+j),它们都与a[i][j]等价,或者还可写成(*(a+i))[j]。

在Turbo C中, 可定义如下的指针变量:
int (*p)[3];
指针p为指向一个由3个元素所组成的整型数组指针。在定义中,圆括号是不能少的, 否则它是指针数组, 这将在后面介绍。

指针数组
int *a[10];
定义了一个指针数组,数组中的每个元素都是指向整型量的指针,该数组由10个元素组成,即 a[0],a[1],a[2], …, a[9],它们均为指针变量。a为该指针数组名,和数组一样,a是常量,不能对它进行增量运算。a为指针数组元素a[0]的地址,a+i为a[i]的地址,*a就是a[0],*(a+i)就是a[i]。

指针函数
当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。
格式:
类型说明符 * 函数名(参数)
当然了,由于返回的是一个地址,所以类型说明符一般都是int。
例如:int *GetDate();

函数指针
指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:
类型说明符 (*函数名)(参数)
其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。
指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
例如:
void (*fptr)();
把函数的地址赋值给函数指针,可以采用下面两种形式:
fptr=&Function;
fptr=Function;
取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
可以采用如下两种方式来通过指针调用函数:
x=(*fptr)();
x=fptr();
第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。

指针的指针
指针的指针看上去有些令人费解。它们的声明有两个星号。例如:
char ** cp;
如果有三个星号,那就是指针的指针的指针,四个星号就是指针的指针的指针的指针,依次类推。当你熟悉了简单的例子以后,就可以应付复杂的情况了。当然,实际程序中,一般也只用到二级指针,三个星号不常见,更别说四个星号了。
指针的指针需要用到指针的地址。
char c=’A';
char *p=&c;
char **cp=&p;
利用指针的指针可以允许被调用函数修改局部指针变量和处理指针数组。

void FindCredit(int **);

main()
{
int vals[]={7,6,5,-4,3,2,1,0};
int *fp=vals;
FindCredit(&fp);
printf(%d\n,*fp);
}

void FindCredit(int ** fpp)
{
while(**fpp!=0)
if(**fpp
=====================
char *Names[]=
{
“Bill”,
“Sam”,
“Jim”,
“Paul”,
“Charles”,
0
};

main()
{
char **nm=Names; /* nm是一个2维字符数组 */
while(*nm!=0) printf(“%s\n”,*nm++); /* *nm是指针,以确定指针指向非null */
/* 对于字符数组,数组名虽然是指针,但是也可以表示整个数组指向的字符串。反而“*数组名“却返回错误Segmentation fault。*/
}

先用字符型指针数组Names的地址来初始化指针nm。每次printf()的调用都首先传递指针nm指向的字符型指针,然后对nm进行自增运算使其指向数组的下一个元素(还是指针)。注意完成上述认为的语法为*nm++,它首先取得指针指向的内容,然后使指针自增。
注意数组中的最后一个元素被初始化为0,while循环以次来判断是否到了数组末尾。具有零值的指针常常被用做循环数组的终止符。程序员称零值指针为空指针(NULL)。

Assigning in C

In C/C++ on November 19, 2008 at 6:09 pm

int main ( int argc, char **argv ){}
int main ( int argc, char *argv ) {}

Quote:
An array of char pointers can be represented as a function parameter one of two ways: char *name[] or char **name. I have chosen to use the latter, you can use either one, it is a matter of style, which I refuse to dictate
#####################
In the code you quoted, the former is correct, the latter is wrong. (But since this is C, both main functions should return 0.)

Under certain circumstances, an array decays to a pointer to its first element. In that way, char **argv and char *argv[] are equivalent.
#####################
char *argv .. u r sending a pointer to a char as an argument..this can be a normal pointer or point to a array of chars…

char **argv .. u r sending a pointer to an array of pointers as an argument . which means, each element of this array can itself point to a char array..

C header definition and declaration

In C/C++, howto on December 3, 2007 at 1:33 am

Structuring header files

  > In the past, I've been told that for every .c file, you should > have a corresponding .h file which will contain all the necessary > definitions, prototypes, etc... for the functions in the file. > Is this the case, or should we just use one global header file > that contains all the prototypes, externs, defines, etc...

The rules are not carved in stone, and should be followed with a grain ofsalt in all specific cases, but here's the usual story:

a) It's always a good idea to play safe against possible multiple inclusions  of the same .h file. This can happen if you #include "foo.h" ,"bar.h", and  bar.h has an "#include "foo.h" line itself.  The canonical way to prevent multiple inclusions is to wrap each header  with an #ifndef CONSTANT directive, and #define that constant in the file  (immediately after). Example:

          /* This is myheader.h */          #ifndef _MYHEADER_          #define _MYHEADER_

          /* All the rest of the header here */

          #endif /* _MYHEADER_ */          /* End of myheader.h */

   The preprocessor will access the "rest of the header" only the first time   the header is included. The second time the _MYHEADER_ constant will be   already defined, causing #ifndef to be false, and the "rest" to be skipped   up to the #endif /* _MYHEADER_ */ line, that is up to the end.

b) .c files should contain relatively small sets of tightly related  functions. Their declarations go in a .h file with the same name, to  be included by all the other .c files that use those functions.

c) Type definitions (typedef, struct) must go in .h files, as soon as they are  used by more than one .c file. Defined type names should visually suggest  that they are not base types (like int or float). An often used convention  is to write their names using caps:       typedef int* Foo;       typedef float GlobeTrotter[3];       typedef struct _BarfBeer {          int a,b;          struct _BarfBeer* next; /* For a linked list */       } BarfBeer;

d) Preprocessor directives defining constants and macros go in .h files as  soon as the constants and macros are used by more than one function (it  annoys me to have to fish through a .c file for the definition of a macro,  and I'd much rather see it in a short .h). Constants used by just one  function are #define-d right before it in the .c file, and #undef-ined  immediately after. Defined constant names should be ALL_IN_CAPS

e) Global variables are declared with the "extern" storage qualifier in .h  files, which are included by all the .c files that need those  globals. There must be only ONE definition for each global variable (i.e. a  declaration without "extern"), and it MUST be in a .c file. If you put it  in a header, you get a multiple definition error as soon as that header is  included by more than one .c file. It doesn't hurt, and greatly helps  code readability, to redeclare at the beginning of a function all extern  variables used by that funciton (of course using the "extern" storage  qualifier).

f) If at all possible, do not include header files in header files, and let  only the .c guys do all the #include-ing.  A non ``flat'', hyerarchical inclusion structure is more suited to C++.

P.S. A "storage qualifier" is a keyword specifying the type of storage needed    for a certain variable. Example of C storage qualifiers are: static,

   extern, register, volatile.

#######################################################

Extern Variables and Functions

Because a global variable may be defined in one file and referred to in other files, some means of telling the compiler that the variable is defined elsewhere may be needed. Otherwise, the compiler may object to the variable as undefined. This is facilitated by an extern declaration. For example, the declaration

extern int size; // variable declaration

informs the compiler that size is actually defined somewhere (may be later in this file or in another file). This is called a variable declaration (not definition) because it does not lead to any storage being allocated for size.

It is a poor programming practice to include an initializer for an extern variable, since this causes it to become a variable definition and have storage allocated for it:

extern int size = 10; // no longer a declaration!

If there is another definition for size elsewhere in the program, it will eventually clash with this one.

Function prototypes may also be declared as extern, but this has no effect when a prototype appears at the global scope. It is more useful for declaring function prototypes inside a function. For example:

double Tangent (double angle)

{

extern double sin(double); // defined elsewhere

extern double cos(double); // defined elsewhere

return sin(angle) / cos(angle);

}

The best place for extern declarations is usually in header files so that they can be easily included and shared by source files.



关于Linux操作系统下C语言编程的注意事项

In C/C++, howto, linux on November 21, 2007 at 12:28 am

关于Linux操作系统下C语言编程的注意事项 — IT技术 – 赛迪网

一、工具的使用

  
1、学会使用vim/emacs,vim/emacs是linux下最常用的源码编辑具,不光要学会用它们编辑源码,还要学会用它们进行查找、定位、替换等。新手的话推荐使用vim,这也是我目前使用的文本编辑器。

  
2、学会makefile文件的编写规则,并结合使用工具aclocal、autoconf和automake生成makefile文件。

  
3、掌握gcc和gdb的基本用法。掌握gcc的用法对于构建一个软件包很有益处,当软件包包含的文件比较多的时候,你还能用gcc把它手动编译出来,你就会对软件包中各个文件间的依赖关系有一个清晰的了解。

  
4、掌握svn/cvs的基本用法。这是linux,也是开源社区最常用的版本管理系统。可以去试着参加sourceforge上的一些开源项目。

  

二、linux/unix系统调用与标准C库

  系统调用应用软件与操作系统的接口,其重要性自然不用说,一定要掌握。推荐学习资料为steven先生的UNIX环境高级编程(简称APUE)。

  

三、库的学习

  无论是在哪个平台做软件开发,对于库的学习都很重要,linux下的开发库很多,我主要介绍一下我常常用到的一些库。

  
1、glib库

  glib 库是gtk+和gnome的基础库,并具是跨平台的,在linux、unix和windows下都可以用。glib库对于linux平台开发的影响就像 MFC对windows平台开发的影响一样,很多开源项目都大量的使用了glib库,包括gimp、gnome、gaim、evolution和 linux下的集群软件heartbeat。因为glib库自带有基本的数据结构实现,所以在学习glib库的时候可以顺便学习一下基本的数据结构(包括链表、树、队列和hash表)。

  
2、libxml库

  libxml是linux平台下解析XML文件的一个基础库,现在很多实用软件都用XML格式的配置文件,所以也有必要学习一下。

  
3、readline库

  readline 库是bash shell用的库,如果要开发命令行程序,那么使用readline库可以减少很多工作量,比如bash里的命令行自动补全,在readline里就已经有实现,当然你也可以用自己的实现替代库的行为。readline库有很多网站介绍的,只要google一下readline就可以找到一堆了。

  
4、curses库

  curses 库以前是vi程序的一部分,后来从vi里提取出来成为一个独立的库。curses库对于编写终端相关的程序特别有用,比如要在终端某一行某一列定位输出,改变终端字体的颜色和终端模式。linux下的curses库用的是GNU实现的ncurses(new curses的意思)。  
5、gtk+和KDE库

  这两个库是开发GUI应用程序的基础库,现在linux下的大部份GUI程序都是基于这两个库开发的,对于它们 的学习也是很有必要的。

  

四、网络的学习

  网络这个东西太宽了,推荐学习资料steven先生的UNIX网络编程(简称UNP)和TCP/IP协议详解,更进一步的话可以学习使用libnet编写网络程序

Powered by ScribeFire.

关于Linux操作系统下C语言编程的注意事项

In C/C++, howto, linux on November 21, 2007 at 12:28 am

关于Linux操作系统下C语言编程的注意事项 — IT技术 – 赛迪网

一、工具的使用

  
1、学会使用vim/emacs,vim/emacs是linux下最常用的源码编辑具,不光要学会用它们编辑源码,还要学会用它们进行查找、定位、替换等。新手的话推荐使用vim,这也是我目前使用的文本编辑器。

  
2、学会makefile文件的编写规则,并结合使用工具aclocal、autoconf和automake生成makefile文件。

  
3、掌握gcc和gdb的基本用法。掌握gcc的用法对于构建一个软件包很有益处,当软件包包含的文件比较多的时候,你还能用gcc把它手动编译出来,你就会对软件包中各个文件间的依赖关系有一个清晰的了解。

  
4、掌握svn/cvs的基本用法。这是linux,也是开源社区最常用的版本管理系统。可以去试着参加sourceforge上的一些开源项目。

  

二、linux/unix系统调用与标准C库

  系统调用应用软件与操作系统的接口,其重要性自然不用说,一定要掌握。推荐学习资料为steven先生的UNIX环境高级编程(简称APUE)。

  

三、库的学习

  无论是在哪个平台做软件开发,对于库的学习都很重要,linux下的开发库很多,我主要介绍一下我常常用到的一些库。

  
1、glib库

  glib 库是gtk+和gnome的基础库,并具是跨平台的,在linux、unix和windows下都可以用。glib库对于linux平台开发的影响就像 MFC对windows平台开发的影响一样,很多开源项目都大量的使用了glib库,包括gimp、gnome、gaim、evolution和 linux下的集群软件heartbeat。因为glib库自带有基本的数据结构实现,所以在学习glib库的时候可以顺便学习一下基本的数据结构(包括链表、树、队列和hash表)。

  
2、libxml库

  libxml是linux平台下解析XML文件的一个基础库,现在很多实用软件都用XML格式的配置文件,所以也有必要学习一下。

  
3、readline库

  readline 库是bash shell用的库,如果要开发命令行程序,那么使用readline库可以减少很多工作量,比如bash里的命令行自动补全,在readline里就已经有实现,当然你也可以用自己的实现替代库的行为。readline库有很多网站介绍的,只要google一下readline就可以找到一堆了。

  
4、curses库

  curses 库以前是vi程序的一部分,后来从vi里提取出来成为一个独立的库。curses库对于编写终端相关的程序特别有用,比如要在终端某一行某一列定位输出,改变终端字体的颜色和终端模式。linux下的curses库用的是GNU实现的ncurses(new curses的意思)。  
5、gtk+和KDE库

  这两个库是开发GUI应用程序的基础库,现在linux下的大部份GUI程序都是基于这两个库开发的,对于它们 的学习也是很有必要的。

  

四、网络的学习

  网络这个东西太宽了,推荐学习资料steven先生的UNIX网络编程(简称UNP)和TCP/IP协议详解,更进一步的话可以学习使用libnet编写网络程序

Powered by ScribeFire.

run System (Shell) command from the program

In C/C++, howto, java, linux on October 17, 2007 at 3:42 pm

1. In C/C++ program
———-

In this short code snippet I will show you how to execute system commands like ping or nslookup or format c: ;-) . The function we will use is rather intended to be used in textconsole based applications. But you could also use it in other programs.

That is our ‘magic’ function. You have to include stdlib.h to use it.

int system( const char *command );

command is a string that holds the app’s name with optional arguments. It is used like on the commandline. The good thing is that the text output that the application produces will be shown in your textconsole. You could now use it to program your own shell! Nice, isn’t it? The return-value will be same as the the return-value of the system command only if there was an error, then it will be -1. Here’s a little example:

#include .h>#include .h>int main(){cout << "Executing ping..." <"ping localhost");cout << "Ping is done. I am done too. Let's shutdown and go for a drink."    < 

This simple code snippet outputs some text and then starts ping with argument localhost. The ouput of ping will be shown in your textconsole and it will be the same as if you run it on the shell.

2. In Java program (quoted from:http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=1)
——————–

As part of the Java language, the java.lang package is implicitly imported into every Java program. This package’s pitfalls surface often, affecting most programmers. This month, I’ll discuss the traps lurking in the Runtime.exec() method.

Pitfall 4: When Runtime.exec() won’t

The class java.lang.Runtime features a static method called getRuntime(), which retrieves the current Java Runtime Environment. That is the only way to obtain a reference to the Runtime object. With that reference, you can run external programs by invoking the Runtime class’s exec() method. Developers often call this method to launch a browser for displaying a help page in HTML.

There are four overloaded versions of the exec() command:

  • public Process exec(String command);
  • public Process exec(String [] cmdArray);
  • public Process exec(String command, String [] envp);
  • public Process exec(String [] cmdArray, String [] envp);

For each of these methods, a command — and possibly a set of arguments — is passed to an operating-system-specific function call. This subsequently creates an operating-system-specific process (a running program) with a reference to a Process class returned to the Java VM. The Process class is an abstract class, because a specific subclass of Process exists for each operating system.

You can pass three possible input parameters into these methods:

  1. A single string that represents both the program to execute and any arguments to that program
  2. An array of strings that separate the program from its arguments
  3. An array of environment variables

Pass in the environment variables in the form name=value. If you use the version of exec() with a single string for both the program and its arguments, note that the string is parsed using white space as the delimiter via the StringTokenizer class.

Stumbling into an IllegalThreadStateException

The first pitfall relating to Runtime.exec() is the IllegalThreadStateException. The prevalent first test of an API is to code its most obvious methods. For example, to execute a process that is external to the Java VM, we use the exec() method. To see the value that the external process returns, we use the exitValue() method on the Process class. In our first example, we will attempt to execute the Java compiler (javac.exe):

Listing 4.1 BadExecJavac.java

import java.util.*;import java.io.*;public class BadExecJavac{public static void main(String args[]){    try    {                Runtime rt = Runtime.getRuntime();        Process proc = rt.exec("javac");        int exitVal = proc.exitValue();        System.out.println("Process exitValue: " + exitVal);    } catch (Throwable t)      {        t.printStackTrace();      }}}

A run of BadExecJavac produces:

E:\classes\com\javaworld\jpitfalls\article2>java BadExecJavacjava.lang.IllegalThreadStateException: process has not exited    at java.lang.Win32Process.exitValue(Native Method)    at BadExecJavac.main(BadExecJavac.java:13)

If an external process has not yet completed, the exitValue() method will throw an IllegalThreadStateException; that’s why this program failed. While the documentation states this fact, why can’t this method wait until it can give a valid answer?

A more thorough look at the methods available in the Process class reveals a waitFor() method that does precisely that. In fact, waitFor() also returns the exit value, which means that you would not use exitValue() and waitFor() in conjunction with each other, but rather would choose one or the other. The only possible time you would use exitValue() instead of waitFor() would be when you don’t want your program to block waiting on an external process that may never complete. Instead of using the waitFor() method, I would prefer passing a boolean parameter called waitFor into the exitValue() method to determine whether or not the current thread should wait. A boolean would be more beneficial because exitValue() is a more appropriate name for this method, and it isn’t necessary for two methods to perform the same function under different conditions. Such simple condition discrimination is the domain of an input parameter.

Therefore, to avoid this trap, either catch the IllegalThreadStateException or wait for the process to complete.

Now, let’s fix the problem in Listing 4.1 and wait for the process to complete. In Listing 4.2, the program again attempts to execute javac.exe and then waits for the external process to complete:

Listing 4.2 BadExecJavac2.java

import java.util.*;import java.io.*;public class BadExecJavac2{public static void main(String args[]){    try    {                Runtime rt = Runtime.getRuntime();        Process proc = rt.exec("javac");        int exitVal = proc.waitFor();        System.out.println("Process exitValue: " + exitVal);    } catch (Throwable t)      {        t.printStackTrace();      }}}

Unfortunately, a run of BadExecJavac2 produces no output. The program hangs and never completes. Why does the javac process never complete?

Why Runtime.exec() hangs

The JDK’s Javadoc documentation provides the answer to this question:

Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.

Is this just a case of programmers not reading the documentation, as implied in the oft-quoted advice: read the fine manual (RTFM)? The answer is partially yes. In this case, reading the Javadoc would get you halfway there; it explains that you need to handle the streams to your external process, but it does not tell you how.

Another variable is at play here, as is evident by the large number of programmer questions and misconceptions concerning this API in the newsgroups: though Runtime.exec() and the Process APIs seem extremely simple, that simplicity is deceiving because the simple, or obvious, use of the API is prone to error. The lesson here for the API designer is to reserve simple APIs for simple operations. Operations prone to complexities and platform-specific dependencies should reflect the domain accurately. It is possible for an abstraction to be carried too far. The JConfig library provides an example of a more complete API to handle file and process operations (see Resources below for more information).

Now, let’s follow the JDK documentation and handle the output of the javac process. When you run javac without any arguments, it produces a set of usage statements that describe how to run the program and the meaning of all the available program options. Knowing that this is going to the stderr stream, you can easily write a program to exhaust that stream before waiting for the process to exit. Listing 4.3 completes that task. While this approach will work, it is not a good general solution. Thus, Listing 4.3’s program is named MediocreExecJavac; it provides only a mediocre solution. A better solution would empty both the standard error stream and the standard output stream. And the best solution would empty these streams simultaneously (I’ll demonstrate that later).

Listing 4.3 MediocreExecJavac.java

import java.util.*;import java.io.*;public class MediocreExecJavac{public static void main(String args[]){    try    {                Runtime rt = Runtime.getRuntime();        Process proc = rt.exec("javac");        InputStream stderr = proc.getErrorStream();        InputStreamReader isr = new InputStreamReader(stderr);        BufferedReader br = new BufferedReader(isr);        String line = null;        System.out.println("");        while ( (line = br.readLine()) != null)            System.out.println(line);        System.out.println("");        int exitVal = proc.waitFor();        System.out.println("Process exitValue: " + exitVal);    } catch (Throwable t)      {        t.printStackTrace();      }}}

A run of MediocreExecJavac generates:

E:\classes\com\javaworld\jpitfalls\article2>java MediocreExecJavac

Usage: javac  where  includes:-g                     Generate all debugging info-g:none                Generate no debugging info-g:{lines,vars,source} Generate only some debugging info-O                     Optimize; may hinder debugging or enlarge class files-nowarn                Generate no warnings-verbose               Output messages about what the compiler is doing-deprecation           Output source locations where deprecated APIs are used-classpath       Specify where to find user class files-sourcepath      Specify where to find input source files-bootclasspath   Override location of bootstrap class files-extdirs         Override location of installed extensions-d          Specify where to place generated class files-encoding    Specify character encoding used by source files-target       Generate class files for specific VM version

Process exitValue: 2

So, MediocreExecJavac works and produces an exit value of 2. Normally, an exit value of 0 indicates success; any nonzero value indicates an error. The meaning of these exit values depends on the particular operating system. A Win32 error with a value of 2 is a “file not found” error. That makes sense, since javac expects us to follow the program with the source code file to compile.

Thus, to circumvent the second pitfall — hanging forever in Runtime.exec() — if the program you launch produces output or expects input, ensure that you process the input and output streams.

Assuming a command is an executable program

Under the Windows operating system, many new programmers stumble upon Runtime.exec() when trying to use it for nonexecutable commands like dir and copy. Subsequently, they run into Runtime.exec()’s third pitfall. Listing 4.4 demonstrates exactly that:

Listing 4.4 BadExecWinDir.java

import java.util.*;import java.io.*;public class BadExecWinDir{public static void main(String args[]){    try    {                Runtime rt = Runtime.getRuntime();        Process proc = rt.exec("dir");        InputStream stdin = proc.getInputStream();        InputStreamReader isr = new InputStreamReader(stdin);        BufferedReader br = new BufferedReader(isr);        String line = null;        System.out.println("");        while ( (line = br.readLine()) != null)            System.out.println(line);        System.out.println("");        int exitVal = proc.waitFor();                System.out.println("Process exitValue: " + exitVal);    } catch (Throwable t)      {        t.printStackTrace();      }}}

A run of BadExecWinDir produces:

E:\classes\com\javaworld\jpitfalls\article2>java BadExecWinDirjava.io.IOException: CreateProcess: dir error=2    at java.lang.Win32Process.create(Native Method)    at java.lang.Win32Process.(Unknown Source)    at java.lang.Runtime.execInternal(Native Method)    at java.lang.Runtime.exec(Unknown Source)    at java.lang.Runtime.exec(Unknown Source)    at java.lang.Runtime.exec(Unknown Source)    at java.lang.Runtime.exec(Unknown Source)    at BadExecWinDir.main(BadExecWinDir.java:12)

As stated earlier, the error value of 2 means “file not found,” which, in this case, means that the executable named dir.exe could not be found. That’s because the directory command is part of the Windows command interpreter and not a separate executable. To run the Windows command interpreter, execute either command.com or cmd.exe, depending on the Windows operating system you use. Listing 4.5 runs a copy of the Windows command interpreter and then executes the user-supplied command (e.g., dir).

Listing 4.5 GoodWindowsExec.java

import java.util.*;import java.io.*;class StreamGobbler extends Thread{InputStream is;String type;

StreamGobbler(InputStream is, String type){    this.is = is;    this.type = type;}

public void run(){    try    {        InputStreamReader isr = new InputStreamReader(is);        BufferedReader br = new BufferedReader(isr);        String line=null;        while ( (line = br.readLine()) != null)            System.out.println(type + ">" + line);        } catch (IOException ioe)          {            ioe.printStackTrace();          }}}public class GoodWindowsExec{public static void main(String args[]){    if (args.length ");        System.exit(1);    }

    try    {                String osName = System.getProperty("os.name" );        String[] cmd = new String[3];        if( osName.equals( "Windows NT" ) )        {            cmd[0] = "cmd.exe" ;            cmd[1] = "/C" ;            cmd[2] = args[0];        }        else if( osName.equals( "Windows 95" ) )        {            cmd[0] = "command.com" ;            cmd[1] = "/C" ;            cmd[2] = args[0];        }

        Runtime rt = Runtime.getRuntime();        System.out.println("Execing " + cmd[0] + " " + cmd[1]                           + " " + cmd[2]);        Process proc = rt.exec(cmd);        // any error message?        StreamGobbler errorGobbler = new            StreamGobbler(proc.getErrorStream(), "ERROR");        

        // any output?        StreamGobbler outputGobbler = new            StreamGobbler(proc.getInputStream(), "OUTPUT");

        // kick them off        errorGobbler.start();        outputGobbler.start();

        // any error???        int exitVal = proc.waitFor();        System.out.println("ExitValue: " + exitVal);        } catch (Throwable t)      {        t.printStackTrace();      }}}

Running GoodWindowsExec with the dir command generates:

E:\classes\com\javaworld\jpitfalls\article2>java GoodWindowsExec "dir *.java"Execing cmd.exe /C dir *.javaOUTPUT> Volume in drive E has no label.OUTPUT> Volume Serial Number is 5C5F-0CC9OUTPUT>OUTPUT> Directory of E:\classes\com\javaworld\jpitfalls\article2OUTPUT>OUTPUT>10/23/00  09:01p                   805 BadExecBrowser.javaOUTPUT>10/22/00  09:35a                   770 BadExecBrowser1.javaOUTPUT>10/24/00  08:45p                   488 BadExecJavac.javaOUTPUT>10/24/00  08:46p                   519 BadExecJavac2.javaOUTPUT>10/24/00  09:13p                   930 BadExecWinDir.javaOUTPUT>10/22/00  09:21a                 2,282 BadURLPost.javaOUTPUT>10/22/00  09:20a                 2,273 BadURLPost1.java... (some output omitted for brevity)OUTPUT>10/12/00  09:29p                   151 SuperFrame.javaOUTPUT>10/24/00  09:23p                 1,814 TestExec.javaOUTPUT>10/09/00  05:47p                23,543 TestStringReplace.javaOUTPUT>10/12/00  08:55p                   228 TopLevel.javaOUTPUT>              22 File(s)         46,661 bytesOUTPUT>                         19,678,420,992 bytes freeExitValue: 0

Running GoodWindowsExec with any associated document type will launch the application associated with that document type. For example, to launch Microsoft Word to display a Word document (i.e., one with a .doc extension), type:

>java GoodWindowsExec "yourdoc.doc"

Notice that GoodWindowsExec uses the os.name system property to determine which Windows operating system you are running — and thus determine the appropriate command interpreter. After executing the command interpreter, handle the standard error and standard input streams with the StreamGobbler class. StreamGobbler empties any stream passed into it in a separate thread. The class uses a simple String type to denote the stream it empties when it prints the line just read to the console.

Thus, to avoid the third pitfall related to Runtime.exec(), do not assume that a command is an executable program; know whether you are executing a standalone executable or an interpreted command. At the end of this section, I will demonstrate a simple command-line tool that will help you with that analysis.

It is important to note that the method used to obtain a process’s output stream is called getInputStream(). The thing to remember is that the API sees things from the perspective of the Java program and not the external process. Therefore, the external program’s output is the Java program’s input. And that logic carries over to the external program’s input stream, which is an output stream to the Java program.

Runtime.exec() is not a command line

One final pitfall to cover with Runtime.exec() is mistakenly assuming that exec() accepts any String that your command line (or shell) accepts. Runtime.exec() is much more limited and not cross-platform. This pitfall is caused by users attempting to use the exec() method to accept a single String as a command line would. The confusion may be due to the fact that command is the parameter name for the exec() method. Thus, the programmer incorrectly associates the parameter command with anything that he or she can type on a command line, instead of associating it with a single program and its arguments. In listing 4.6 below, a user tries to execute a command and redirect its output in one call to exec():

Listing 4.6 BadWinRedirect.java

import java.util.*;import java.io.*;// StreamGobbler omitted for brevitypublic class BadWinRedirect{public static void main(String args[]){    try    {                Runtime rt = Runtime.getRuntime();        Process proc = rt.exec("java jecho 'Hello World' > test.txt");        // any error message?        StreamGobbler errorGobbler = new            StreamGobbler(proc.getErrorStream(), "ERROR");        

        // any output?        StreamGobbler outputGobbler = new            StreamGobbler(proc.getInputStream(), "OUTPUT");

        // kick them off        errorGobbler.start();        outputGobbler.start();

        // any error???        int exitVal = proc.waitFor();        System.out.println("ExitValue: " + exitVal);        } catch (Throwable t)      {        t.printStackTrace();      }}}

Running BadWinRedirect produces:

E:\classes\com\javaworld\jpitfalls\article2>java BadWinRedirectOUTPUT>'Hello World' > test.txtExitValue: 0

The program BadWinRedirect attempted to redirect the output of an echo program’s simple Java version into the file test.txt. However, we find that the file test.txt does not exist. The jecho program simply takes its command-line arguments and writes them to the standard output stream. (You will find the source for jecho in the source code available for download in Resources.) In Listing 4.6, the user assumed that you could redirect standard output into a file just as you could on a DOS command line. Nevertheless, you do not redirect the output through this approach. The incorrect assumption here is that the exec() method acts like a shell interpreter; it does not. Instead, exec() executes a single executable (a program or script). If you want to process the stream to either redirect it or pipe it into another program, you must do so programmatically, using the java.io package. Listing 4.7 properly redirects the standard output stream of the jecho process into a file.

Listing 4.7 GoodWinRedirect.java

import java.util.*;import java.io.*;class StreamGobbler extends Thread{InputStream is;String type;OutputStream os;

StreamGobbler(InputStream is, String type){    this(is, type, null);}StreamGobbler(InputStream is, String type, OutputStream redirect){    this.is = is;    this.type = type;    this.os = redirect;}

public void run(){    try    {        PrintWriter pw = null;        if (os != null)            pw = new PrintWriter(os);

        InputStreamReader isr = new InputStreamReader(is);        BufferedReader br = new BufferedReader(isr);        String line=null;        while ( (line = br.readLine()) != null)        {            if (pw != null)                pw.println(line);            System.out.println(type + ">" + line);        }        if (pw != null)            pw.flush();    } catch (IOException ioe)        {        ioe.printStackTrace();        }}}public class GoodWinRedirect{public static void main(String args[]){    if (args.length ");        System.exit(1);    }

    try    {                FileOutputStream fos = new FileOutputStream(args[0]);        Runtime rt = Runtime.getRuntime();        Process proc = rt.exec("java jecho 'Hello World'");        // any error message?        StreamGobbler errorGobbler = new            StreamGobbler(proc.getErrorStream(), "ERROR");        

        // any output?        StreamGobbler outputGobbler = new            StreamGobbler(proc.getInputStream(), "OUTPUT", fos);

        // kick them off        errorGobbler.start();        outputGobbler.start();

        // any error???        int exitVal = proc.waitFor();        System.out.println("ExitValue: " + exitVal);        fos.flush();        fos.close();        } catch (Throwable t)      {        t.printStackTrace();      }}}

Running GoodWinRedirect produces:

E:\classes\com\javaworld\jpitfalls\article2>java GoodWinRedirect test.txtOUTPUT>'Hello World'ExitValue: 0

After running GoodWinRedirect, test.txt does exist. The solution to the pitfall was to simply control the redirection by handling the external process’s standard output stream separately from the Runtime.exec() method. We create a separate OutputStream, read in the filename to which we redirect the output, open the file, and write the output that we receive from the spawned process’s standard output to the file. Listing 4.7 completes that task by adding a new constructor to our StreamGobbler class. The new constructor takes three arguments: the input stream to gobble, the type String that labels the stream we are gobbling, and the output stream to which we redirect the input. This new version of StreamGobbler does not break any of the code in which it was previously used, as we have not changed the existing public API — we only extended it.

Since the argument to Runtime.exec() is dependent on the operating system, the proper commands to use will vary from one OS to another. So, before finalizing arguments to Runtime.exec() and writing the code, quickly test the arguments. Listing 4.8 is a simple command-line utility that allows you to do just that.

Here’s a useful exercise: try to modify TestExec to redirect the standard input or standard output to a file. When executing the javac compiler on Windows 95 or Windows 98, that would solve the problem of error messages scrolling off the top of the limited command-line buffer.

Listing 4.8 TestExec.java

import java.util.*;import java.io.*;// class StreamGobbler omitted for brevitypublic class TestExec{public static void main(String args[]){    if (args.length 

Running TestExec to launch the Netscape browser and load the Java help documentation produces:

E:\classes\com\javaworld\jpitfalls\article2>java TestExec "e:\java\docs\index.html"java.io.IOException: CreateProcess: e:\java\docs\index.html error=193    at java.lang.Win32Process.create(Native Method)    at java.lang.Win32Process.(Unknown Source)    at java.lang.Runtime.execInternal(Native Method)    at java.lang.Runtime.exec(Unknown Source)    at java.lang.Runtime.exec(Unknown Source)    at java.lang.Runtime.exec(Unknown Source)    at java.lang.Runtime.exec(Unknown Source)    at TestExec.main(TestExec.java:45)

Our first test failed with an error of 193. The Win32 error for value 193 is “not a valid Win32 application.” This error tells us that no path to an associated application (e.g., Netscape) exists, and that the process cannot run an HTML file without an associated application.

Therefore, we try the test again, this time giving it a full path to Netscape. (Alternately, we could add Netscape to our PATH environment variable.) A second run of TestExec produces:

E:\classes\com\javaworld\jpitfalls\article2>java TestExec"e:\program files\netscape\program\netscape.exe e:\java\docs\index.html"ExitValue: 0

This worked! The Netscape browser launches, and it then loads the Java help documentation.

One additional improvement to TestExec would include a command-line switch to accept input from standard input. You would then use the Process.getOutputStream() method to pass the input to the spawned external program.

To sum up, follow these rules of thumb to avoid the pitfalls in Runtime.exec():

  1. You cannot obtain an exit status from an external process until it has exited
  2. You must immediately handle the input, output, and error streams from your spawned external process
  3. You must use Runtime.exec() to execute programs
  4. You cannot use Runtime.exec() like a command line

C with input argue

In C/C++, howto on April 20, 2007 at 9:38 pm

main(int argc,char *argv[])
{
char b[10];int c,d;

strcpy(b,argv[1]);/*get the first parameter*/

c=atoi(b);/*convert string to numbers*/
d=c+1;

printf(“argv[1] is %s\n\n”,b);
printf(“convert argv[1] is %d\n”,c);
printf(“d=c+1 is %d\n”,d);
}