Linux编程之一:创建第一个C/C++程序

来源:互联网 发布:久其数据 编辑:程序博客网 时间:2024/06/06 12:22

最近开始学习Linux编程,想为以后的嵌入式Linux开发开个们,开到一篇不错的博客,就转过来了。

我用的Linux发行版是Ubuntu.

1,如下图是在linux桌面新建了hello.c,里面编写了helloworld的小程序。
linux下运行的第一个helloworld。

linux下运行的第一个helloworld。

2然后用gcc编译器进行编译,编译后得到可执行文件a.out(这是在未指定文件名的情况下的默认名字)。然后./执行文件。可以看到输出helloworld!
linux下运行的第一个helloworld。

3,用-o参数指定编译文件的名字。如下为hello.exe
linux下运行的第一个helloworld。
4,执行可以看到输出结果********
linux下运行的第一个helloworld。

5,gcc编译器,g++编译器和gdb调试器

 

GNU程序编译

命令:gcc

g++

 

格式:gcc [option] filename

g++ [option] filename

 

功能:编译或链接指定的编译文件。

 

选项:-o 指定输出文件名,缺省时为a.out

-c 只编译,产生.o的目标文件

-O 进行代码的一般优化

-O2 二级优化

 

一.C语言程序的编译——gcc用法的详细说明

摘自:OwnLinux.cn

   GNU 编译器集(其前身为GNU C 编译器)诞生于1987年。当时Richard Stallman(GNU 项目的创办人)想要创建一个编译器,它可以满足他定义的“自由软件”概念,并可用来编译 GNU 项目发布的其他软件。GNU C 编译器迅速在自由软件社区中流行开来,而且以其健壮性和可移植性而闻名。它已成为许多集成开发工具的基础,被世界各地的发行商应用在 Linux 和其他操作系统之上。

 

GCC 已不再是主要针对GNU项目自身的软件的小型 C 语言编译器了。如今,它已支持了许多不同的语言,包括 C、C++、Ada、Fortran、Objective C,甚至还有Java。事实上,现代 Linux 系统除了可以自豪地炫耀那些由 GNU 工具直接支持的语言以外,它还支持大量其他语言。日益流行的脚本语言 Perl、Python 和 Ruby,以及正在不断发展的mono 可移植C#实现的确有助于冲淡人们对 Linux 编程的传统看法,但这完全是另外一个问题了。

 

Linux 内核和许多其他自由软件以及开放源码应用程序都是用 C 语言编写并使用 GCC 编译的。

 

1. 编译单个源文件

 

为了进行测试,你可以创建“Hello World”程序:

 

#include

#include

 

int main(int argc, char **argv)

{

printf(”Hello world!\n”);

exit(0);

}

 

使用如下命令编译并测试这个代码:

# gcc -o hello hello.c

# ./hello

Hello wordl!

 

在默认情况下产生的可执行程序名为a.out,但你通常可以通过 gcc 的“-o”选项来指定自己的可执行程序名称。

 

2. 编译多个源文件

 

源文件message.c包含一个简单的消息打印函数:

 

#include

 

void goodbye_world(void)

{

printf(”Goodbye, world!\n”);

}

 

使用gcc的“-c”标记来编译支持库代码:

# gcc -c message.c

 

这一过程的输出结果是一个名为message.o的文件,它包含适合连接到一个较大程序的已编译目标代码。

 

创建一个简单的示例程序,它包含一个调用goodbye_world的main函数

 

#include

void goodbye_world(void):

int main(int argc, char **argv)

{

goodbye_world();

exit(0);

}

 

使用GCC编译这个程序:

# gcc -c main.c

 

现在有了两个目标文件: message.o 和 main.o 。它们包含能够被 Linux 执行的目标代码。要从这个目标代码创建Linux可执行程序,需要再一次调用 GCC 来执行连接阶段的工作:

# gcc -o goodbye message.o main.o

 

运行编译结果:

# ./goodbye

Goodbye, world!

 

前面这些单独的步骤也可以简化为一个命令,这是因为 GCC 对如何将多个源文件编译为一个可执行程序有内置的规则。

# gcc -o goodbye message.c main.c

# ./goodbye

Goodbye, world!

 

二、C++程序的编译—— g++用法的详细说明

C++编译

 1. 单个源文件生成可执行程序

下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码:

 

#include

using namespace std;

int main(int argc, char *argv[])

{

 cout << "hello, world" << endl;

 return 0;

}

程序使用定义在头文件 iostream 中的 cout,向标准输出写入一个简单的字符串。该代码可用以下命令编译为可执行文件:

 

 g++ helloworld.cpp

编译器 g++ 通过检查命令行中指定的文件的后缀名可识别其为 C++ 源代码文件。编译器默认的动作:编译源代码文件生成对象文件(object file),链接对象文件和 libstdc++ 库中的函数得到可执行程序。然后删除对象文件。由于命令行中未指定可执行程序的文件名,编译器采用默认的 a.out。程序可以这样来运行:

$ ./a.out

hello, world

更普遍的做法是通过 -o 选项指定可执行程序的文件名。下面的命令将产生名为 helloworld 的可执行文件:

$ g++ helloworld.cpp -o helloworld

在命令行中输入程序名可使之运行:

$ ./helloworld

hello, world

程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。 

在大多数系统中,GCC 安装时会安装一名为 c++ 的程序。如果被安装,它和 g++ 是等同,如下例所示,用法也一致:

$ c++ helloworld.cpp -o helloworld

 

2. 多个源文件生成可执行程序

如果多于一个的源码文件在 g++ 命令中指定,它们都将被编译并被链接成一个单一的可执行文件。下面是一个名为 speak.h 的头文件;它包含一个仅含有一个函数的类的定义:

 

#include

class Speak

{

 public:

 void sayHello(const char *);

};

下面列出的是文件 speak.cpp 的内容:包含 sayHello() 函数的函数体:

 

#include "speak.h"

using namespace std;

void Speak::sayHello(const char *str)

{

    cout << "Hello " << str << "\n";

}

文件 hellospeak.cpp 内是一个使用 Speak 类的程序:

 

#include "speak.h"

using namespace std;

int main(int argc,char *argv[])

{

    Speak speak;

    speak.sayHello("world");

    return(0);

}

下面这条命令将上述两个源码文件编译链接成一个单一的可执行程序:

$ g++ hellospeak.cpp speak.cpp -o hellospeak

PS:这里说一下为什么在命令中没有提到“speak.h“该文件(原因是:在“speak.cpp“中包含有”#include"speak.h"“这句代码,它的意思是搜索系统头文件目录之前将先在当前目录中搜索文件“speak.h“。而”speak.h“正在该目录中,不用再在命令中指定了)。

 

源文件生成对象文件

选项 -c 用来告诉编译器编译源代码但不要执行链接,输出结果为对象文件。文件默认名与源码文件名相同,只是将其后缀变为 .o。例如,下面的命令将编译源码文件 hellospeak.cpp 并生成对象文件 hellospeak.o:

$ g++ -c hellospeak.cpp

命令 g++ 也能识别 .o 文件并将其作为输入文件传递给链接器。下列命令将编译源码文件为对象文件并将其链接成单一的可执行程序:

$ g++ -c hellospeak.cpp

$ g++ -c speak.cpp

$ g++ hellospeak.o speak.o -o hellospeak

选项 -o 不仅仅能用来命名可执行文件。它也用来命名编译器输出的其他文件。例如:除了中间的对象文件有不同的名字外,下列命令生将生成和上面完全相同的可执行文件:

$ g++ -c hellospeak.cpp -o hspk1.o

$ g++ -c speak.cpp -o hspk2.o

$ g++ hspk1.o hspk2.o -o hellospeak

 

编译预处理

选项 -E 使 g++ 将源代码用编译预处理器处理后不再执行其他动作。下面的命令预处理源码文件 helloworld.cpp 并将结果显示在标准输出中:

$ g++ -E helloworld.cpp

本文前面所列出的 helloworld.cpp 的源代码,仅仅有六行,而且该程序除了显示一行文字外什么都不做,但是,预处理后的版本将超过 1200 行。这主要是因为头文件 iostream 被包含进来,而且它又包含了其他的头文件,除此之外,还有若干个处理输入和输出的类的定义。

预处理过的文件的 GCC 后缀为 .ii,它可以通过 -o 选项来生成,例如:

$ gcc -E helloworld.cpp -o helloworld.ii

生成汇编代码

选项 -S 指示编译器将程序编译成汇编语言,输出汇编语言代码而后结束。下面的命令将由 C++ 源码文件生成汇编语言文件 helloworld.s:

$ g++ -S helloworld.cpp

生成的汇编语言依赖于编译器的目标平台。

创建静态库

静态库是编译器生成的一系列对象文件的集合。链接一个程序时用库中的对象文件还是目录中的对象文件都是一样的。库中的成员包括普通函数,类定义,类的对象实例等等。静态库的另一个名字叫归档文件(archive),管理这种归档文件的工具叫 ar 。

在下面的例子中,我们先创建两个对象模块,然后用其生成静态库。

头文件 say.h 包含函数 sayHello() 的原型和类 Say 的定义:

 

#include

using namespace std;

void sayhello(void);

class Say {

    private:

        char *string;

    public:

        Say(char *str)

        {

            string = str;

        }

        void sayThis(const char *str)

        {

            cout << str << " from a static library\n";

        }

        void sayString(void);

};

下面是文件 say.cpp 是我们要加入到静态库中的两个对象文件之一的源码。它包含 Say 类中 sayString() 函数的定义体;类 Say 的一个实例 librarysay 的声明也包含在内:

 

#include "say.h"

using namespace std;

void Say::sayString()

{

    cout << string << "\n";

}

 

源码文件 sayhello.cpp 是我们要加入到静态库中的第二个对象文件的源码。它包含函数 sayhello() 的定义:

 

#include "say.h"

using namespace std;

void sayhello()

{

    cout << "hello from a static library\n";

}

下面的命令序列将源码文件编译成对象文件,命令 ar 将其存进库中:

$ g++ -c sayhello.cpp

$ g++ -c say.cpp

$ ar -r libsay.a sayhello.o say.o

程序 ar 配合参数 -r 创建一个新库 libsay.a 并将命令行中列出的对象文件插入。采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。

下面是主程序 saymain.cpp,它调用库 libsay.a 中的代码:

 

#include "say.h"

int main(int argc,char *argv[])

{

    sayhello();

    Say localsay = Say("Local instance of Say");

    localsay.sayString();

    localsay.sayThis("Good Morning ");

    return(0);

}

该程序可以下面的命令来编译和链接:

$ g++ saymain.cpp libsay.a -o saymain

程序运行时,产生以下输出:

hello from a static library

Local instance of Say

Good Morning from a static library

 

三GNU 的调试器称 gdb

GNU 的调试器称为 gdb,该程序是一个交互式工具,工作在字符模式。在 X Window 系统中,有一个 gdb 的
前端图形工具,称为 xxgdb。gdb 是功能强大的调试程序,可完成如下的调试任务:
* 设置断点;
* 监视程序变量的值;
* 程序的单步执行;
* 修改变量的值。
在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源文件。可在 makefile 中如下定义 CFLAGS 变量:
CFLAGS = -g
运行 gdb 调试程序时通常使用如下的命令:
gdb progname

在 gdb 提示符处键入help,将列出命令的分类,主要的分类有:
* aliases:命令别名
* breakpoints:断点定义;
* data:数据查看;
* files:指定并查看文件;
* internals:维护命令;
* running:程序执行;
* stack:调用栈查看;
* statu:状态查看;
* tracepoints:跟踪程序执行。
键入 help 后跟命令的分类名,可获得该类命令的详细清单。


#DENO#
gdb 的常用命令
表 1-4 常用的 gdb 命令
命令 解释
break NUM 在指定的行上设置断点。
bt 显示所有的调用栈帧。该命令可用来显示函数的调用顺序。
clear 删除设置在特定源文件、特定行上的断点。其用法为:clear FILENAME:NUM。
continue 继续执行正在调试的程序。该命令用在程序由于处理信号或断点而
导致停止运行时。
display EXPR 每次程序停止后显示表达式的值。表达式由程序定义的变量组成。
file FILE 装载指定的可执行文件进行调试。 


0 0
原创粉丝点击