|
linux下的C语言开发
2021年12月09日 |
|
看到一个很好的文章,学习记录一下,原文链接可以在最后找到
(1)完善的编译环境,包括gcc、as、ld等编译、链接工具 当然,不管我怎么说,最终朋友们还是应该自己勇敢地跨出前进的第一步。
#include <stdio.h>
int main()
{
printf("hello!\n");
return 1;
}
编写完上面的代码后,你需要做的就是两个步骤: 当然,我们不会满足于这么简单的打印功能。下面就可以编写一个简单的迭代函数,
#include <stdio.h>
int iterate(int value)
{
if(1 == value)
return 1;
return iterate(value - 1) + value;
}
int main()
{
printf("%d\n", iterate(10));
return 1;
}
此时,同样我们需要重复上面的步骤: 当然, 还会有一些朋友对程序的反汇编感兴趣,那么他需要两个步骤:
int iterate(int value)
{
8048374: 55 push %ebp
8048375: 89 e5 mov %esp,%ebp
8048377: 83 ec 08 sub $0x8,%esp
if(1 == value)
804837a: 83 7d 08 01 cmpl $0x1,0x8(%ebp)
804837e: 75 09 jne 8048389 <iterate+0x15>
return 1;
8048380: c7 45 fc 01 00 00 00 movl $0x1,0xfffffffc(%ebp)
8048387: eb 16 jmp 804839f <iterate+0x2b>
return iterate(value -1) + value;
8048389: 8b 45 08 mov 0x8(%ebp),%eax
804838c: 83 e8 01 sub $0x1,%eax
804838f: 89 04 24 mov %eax,(%esp)
8048392: e8 dd ff ff ff call 8048374 <iterate>
8048397: 8b 55 08 mov 0x8(%ebp),%edx
804839a: 01 c2 add %eax,%edx
804839c: 89 55 fc mov %edx,0xfffffffc(%ebp)
804839f: 8b 45 fc mov 0xfffffffc(%ebp),%eax
}
80483a2: c9 leave
80483a3: c3 ret
linux下的C语言开发(makefile编写) 首先编写add.c文件,
#include "test.h"
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
printf(" 2 + 3 = %d\n", add(2, 3));
printf(" 2 - 3 = %d\n", sub(2, 3));
return 1;
}
再编写sub.c文件,
#include "test.h"
int sub(int a, int b)
{
return a - b;
}
最后编写test.h文件,
#ifndef _TEST_H
#define _TEST_H
int add(int a, int b);
int sub(int a, int b);
#endif
那么,就是这三个简单的文件,应该怎么编写makefile呢?
test:
add.o sub.o
gcc -o test add.o sub.o
add.o:
add.c test.h
gcc -c add.c
sub.o:
sub.c test.h
gcc -c sub.c
clean:
rm -rf test
rm -rf *.o
linux下的C语言开发(gdb调试)
#include <stdio.h>
int iterate(int value)
{undefined
if(1 == value)
return 1;
return iterate(value - 1) + value;
}
int main()
{undefined
printf("%d\n", iterate(10));
return 1;
}
既然需要调试,那么生成的可执行文件就需要包含调试的信息,这里应该怎么做呢?很简单,输入 gcc test.c -g -o test。输入命令之后,如果没有编译和链接方面的错误,你就可以看到 可执行文件test了。 调试的步骤基本如下所示, linux下的C语言开发(AT&T 汇编语言)
.data
message: .string "hello!\n"
length = . - message
.text
.global _start
_start:
movl $length, %edx
movl $message, %ecx
movl $1, %ebx
movl $4, %eax
int $0x80
movl $0, %ebx
movl $1, %eax
int $0x80
08048074 <_start>:
.text
.global _start
_start:
movl $length, %edx
8048074: ba 08 00 00 00 mov $0x8,%edx
movl $message, %ecx
8048079: b9 9c 90 04 08 mov $0x804909c,%ecx
movl $1, %ebx
804807e: bb 01 00 00 00 mov $0x1,%ebx
movl $4, %eax
8048083: b8 04 00 00 00 mov $0x4,%eax
int $0x80
8048088: cd 80 int $0x80
movl $0, %ebx
804808a: bb 00 00 00 00 mov $0x0,%ebx
movl $1, %eax
804808f: b8 01 00 00 00 mov $0x1,%eax
int $0x80
8048094: cd 80 int $0x80
ret
8048096: c3 ret
这是一个简单的汇编文件,我们可以分两步进行编译。首先,输入 as -gstabs -o hello.o hello.s, 接着输入ld -o hello hello.o即可。为了验证执行文件是否正确,可以输入./hello验证一下。 linux下的C语言开发(静态库)
#include "test.h"
int add(int a, int b)
{
return a + b;
}
头文件代码也不难,
#ifndef _TEST_H
#define _TEST_H
int add(int a, int b);
#endif
如果你需要在windows上面创建一个静态库,那么你需要进行下面的操作, 那么,在linux下面应该怎么运行呢?其实很简单,两条命令解决, 此时如果还有一个hello.c文件使用到了这个静态库,比如说 ,
#include <stdio.h>
#include "test.h"
int main()
{
printf("%d\n", add(2, 3));
return 1;
}
其实也很简单,输入一个简单的命令就可以生成执行文件了, linux下的C语言开发(动态库) 那么,在Linux上动态库是怎么生成的呢?
#include "test.h"
int add(int a, int b)
{
return a + b;
}
头文件格式,
#ifndef _TEST_H
#define _TEST_H
int add(int a, int b);
#endif
此时如果我们想要生成动态库,要做的工作其实非常简单,输入gcc -shared -fPIC -o libtest.so test.c即可。回车后输入ls,我们就可以发现当前目录下面出现了libtest.so文件。
#include <stdio.h>
#include "test.h"
int main()
{
printf("%d\n", add(2, 3));
return 1;
}
在上面的代码当中,我们发现使用到了add函数,那么此时如何才能生成一个执行文件呢?也很简单,输入gcc hello.c -o hello ./libtest.so。然后输入./hello,此时可以验证一下执行文件运行是否正确。在编写静态库的时候,我说过静态库是汇编链接到执行文件当中的,而动态库不会。朋友们可以做个小实验,删除libtest.so,然后输入./hello。此时大家可以看看系统有没有错误返回?
#ifndef _TEST_H
#define _TEST_H
#ifdef USR_DLL
#define DLL_API _declspec(dllexport)
#else
#define DLL_API _declspec(dllimport)
#endif
DLL_API int add(int a, int b);
#endif
linux下的C语言开发(定时器)
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
static int count = 0;
static struct itimerval oldtv;
void set_timer()
{
struct itimerval itv;
itv.it_interval.tv_sec = 1;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 1;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, &oldtv);
}
void signal_handler(int m)
{
count ++;
printf("%d\n", count);
}
int main()
{
signal(SIGALRM, signal_handler);
set_timer();
while(count < 10000);
exit(0);
return 1;
}
linux下的C语言开发(自动编译工具) (1)首先,编写源文件hello.c。
#include <stdio.h>
int main(int argc, char** argv[])
{
printf("hello, world!\n");
return 1;
}
(2)接下来,我们需要创建一个Makefile.am,同时编写上脚本。
SUBDIRS=
bin_PROGRAMS=hello
hello_SOURCES=hello.c
(3)直接输入autoscan,生成文件configure.scan,再改名为configure.in。修改脚本AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)为AC_INIT(hello, 1.0, feixiaoxing@163.com)同时,在AC_CONFIG_HEADER([config.h])后面添加AM_INIT_AUTOMAKE(hello, 0.1) linux下的C语言开发(进程创建)
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
if(-1 == (pid = fork())) {
printf("Error happened in fork function!\n");
return 0;
}
if(0 == pid) {
printf("This is child process: %d\n", getpid());
} else {
printf("This is parent process: %d\n", getpid());
}
return 0;
}
linux下的C语言开发(进程等待)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
pid_t pid;
pid = fork();
if(0 == pid) {
printf("This is child process, %d\n", getpid());
sleep(5);
} else {
wait(NULL);
printf("This is parent process, %d\n", getpid());
}
return 1;
}
下面,我们需要做的就是两步,首先输入gcc fork.c -o fork, 然后输入./fork,就会在console下面获得这样的结果。
[root@localhost fork]# ./fork
This is child process, 2135
This is parent process, 2134
linux下的C语言开发(信号处理)
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int value = 0;
void func(int sig)
{
printf("I get a signal!\n");
value = 1;
}
int main()
{
signal(SIGINT, func);
while(0 == value)
sleep(1);
return 0;
}
为了显示linux对signal的处理流程,我们需要进行两个步骤。
[root@localhost fork]#./sig
I get a signal!
[root@localhost fork]#
linux下的C语言开发(管道通信)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int pipe_default[2];
int main()
{
pid_t pid;
char buffer[32];
memset(buffer, 0, 32);
if(pipe(pipe_default) < 0) {
printf("Failed to create pipe!\n");
return 0;
}
if(0 == (pid = fork())) {
close(pipe_default[1]);
sleep(5);
if(read(pipe_default[0], buffer, 32) > 0) {
printf("Receive data from server, %s!\n", buffer);
}
close(pipe_default[0]);
} else {
close(pipe_default[0]);
if(-1 != write(pipe_default[1], "hello", strlen("hello"))) {
printf("Send data to client, hello!\n");
}
close(pipe_default[1]);
waitpid(pid, NULL, 0);
}
return 1;
}
下面我们就可以开始编译运行了,老规矩分成两步骤进行:
[test@localhost pipe]$ ./pipe
Send data to client, hello!
Receive data from server, hello!
linux下的C语言开发(多线程编程)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
void func_1(void* args)
{
while(1) {
sleep(1);
printf("this is func_1!\n");
}
}
void func_2(void* args)
{
while(1) {
sleep(2);
printf("this is func_2!\n");
}
}
int main()
{
pthread_t pid1, pid2;
if(pthread_create(&pid1, NULL, func_1, NULL)) {
return -1;
}
if(pthread_create(&pid2, NULL, func_2, NULL)) {
return -1;
}
while(1) {
sleep(3);
}
return 0;
}
和我们以前编写的程序有所不同,多线程代码需要这样编译,输入gcc thread.c -o thread -lpthread,编译之后你就可以看到thread可执行文件,输入./thread即可。
[test@localhost Desktop]$ ./thread
this is func_1!
this is func_2!
this is func_1!
this is func_1!
this is func_2!
this is func_1!
this is func_1!
this is func_2!
this is func_1!
this is func_1!
linux下的C语言开发(线程等待)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
void func(void* args)
{
sleep(2);
printf("this is func!\n");
}
int main()
{
pthread_t pid;
if(pthread_create(&pid, NULL, func, NULL)) {
return -1;
}
pthread_join(pid, NULL);
printf("this is end of main!\n");
return 0;
}
编写wait.c文件结束之后,我们就可以开始编译了。首先你需要输入gcc wait.c -o wait -lpthread,编译之后你就可以看到wait可执行文件,输入./wait即可。
[test@localhost thread]$ ./thread
this is func!
this is end of main!
linux下的C语言开发(线程互斥)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
static int value = 0;
pthread_mutex_t mutex;
void func(void* args)
{
while(1) {
pthread_mutex_lock(&mutex);
sleep(1);
value ++;
printf("value = %d!\n", value);
pthread_mutex_unlock(&mutex);
}
}
int main()
{
pthread_t pid1, pid2;
pthread_mutex_init(&mutex, NULL);
if(pthread_create(&pid1, NULL, func, NULL)) {
return -1;
}
if(pthread_create(&pid2, NULL, func, NULL)) {
return -1;
}
while(1)
sleep(0);
return 0;
}
编写mutex.c文件结束之后,我们就可以开始编译了。首先你需要输入gcc mutex.c -o mutex -lpthread,编译之后你就可以看到mutex可执行文件,输入./mutex即可。
[test@localhost thread]$ ./mutex
value = 1!
value = 2!
value = 3!
value = 4!
value = 5!
value = 6!
linux下的C语言开发(网络编程) 在开始介绍网络编程的方法之前,我们可以回忆一下计算机网络的相关知识。目前为止,我们使用的最多网络协议还是tcp/ip网络。通常来说,我们习惯上称为tcp/ip协议栈。至于协议栈分成几层,有两种说法。一种是五层,一种是七层,我个人本身也比较倾向于五层的划分方法。大家可以通过下面的图看看协议栈是怎么划分的。 5、应用层 网络的不同层次实现网络的不同功能。物理层主要实现报文的成帧处理;数据链路层完成对报文的优先级的管理,同时实现二层转发和流量控制;网络层实现路由和转发的功能,一方面它需要实现对报文的fragment处理,另外一方面它还需要对路由信息进行处理和保存;传输层实现报文的发送和接受,它利用计数、时序、定时器、重发等机制实现对报文的准确发送,当然这都是tcp的发送机制,而udp一般是不保证报文正确发送和接收的;应用层就是根据传输层的端口信息调用不同的程序来处理传输的内容,端口8080是http报文,端口21是ftp报文等等。上面的逻辑稍显复杂,朋友们可以这么理解, 作为服务器程序而言,它要对特定的端口进行绑定和侦听处理,这样稍显复杂。但是如果是编写客户端的程序,一切的一切就变得非常简单了, 上面只是对网络编程做了一个基本的介绍,但是好多的东西还是没有涉及到,比如说: 参考文章:https://blog.csdn.net/weixin_40756041/article/details/88112872 |