Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

Friday, 11 March 2016

C fgets bait

I wrote a little program which count the char in a text given, and put it into buffer to return.
It just open the file then use a fgetc() loop  to count char number, then invoke fgets() to put the content into buffer with a size of char number.


char *read_dna_file(char* filename)
{
 unsigned size = 0, line = 0;
 char* buffer = NULL;
 FILE *fstream = fopen(filename, "r");

 if(fstream == NULL)
  return NULL;
 else
 {
  while(fgetc(fstream) != EOF)
   size++;
 }
  printf("%d\n",size);
  buffer = (char*)malloc(size + 1);
  char* code = fgets(buffer, size, fstream);
  fclose(fstream);
 return code;
}

int main()
{
 char* temp = read_dna_file("dna-moutarde.txt");
 printf("%s\n",temp);
}
Segmentation Fault

At the beginning, I had always the same error, segmentation fault, I have no idea where is the problem. With the help of my friend, he point out that the fgetc() will store the address the last time used, when fgets() is invoked, fgets() will continue to read the file from the last position saved.
So the solution is:
Close the file and reopen it. fgets() will read from the beginning of file, or use fseek() to shift the pointer to the beginning. And it works.



char *read_dna_file(char* filename)
{
 unsigned size = 0, line = 0;
 char* buffer = NULL;
 FILE *fstream = fopen(filename, "r");

 if(fstream == NULL)
  return NULL;
 else
 {
  while(fgetc(fstream) != EOF)
   size++;
 }
  printf("%d\n",size);
  fseek(fstream, 0, SEEK_SET); 
  //            OR
 //  fclose(fstream);
//         fstream = fopen(filename, "r");
  buffer = (char*)malloc(size + 1);
  char* code = fgets(buffer, size, fstream);
  fclose(fstream);
 return code;
}

int main()
{

 char* temp = read_dna_file("dna-moutarde.txt");
 printf("%s\n",temp);
}

Thursday, 19 November 2015

C网络编程基础

这两个星期万恶的ACU们又下达新的作业了,是写一个httpd服务器/客户端的project。
首先我要了解IOS模型,之前两年都在学这个模型我已经熟悉了。其次是socket API, 进程和线程的并行。

sockets API:
 Linux中的网络通过socket接口实现,socket是一种特殊的IO,也是一个file discriptor。一个完整的sockets都有一个相关的描述(协议,本地地址,本地端口,远程地址,远程端口)。每个端口都有本地唯一的sockets号,由系统分配。
- 应用: #incldue
      int socket(int domain,int type, int protocol)
      int domain:AF_INET =>internet IPv4
             AF_INET6 = IPv6
      int type: SOCK_STREAM = transfer in bytes stream
             SOCK_DGRAM =   transfer in bytes stream without checking
      int protocol: 0 =  lets system choose which protocol will be used.

 -基本套接字系统调有有如下一些:    
创建套接字: socket()    
绑定本机端口: bind()    
建立连接: connect(),accept()    
侦听端口: listen()    
数据传输: send(), recv()    
输入/输出多路复用: select()    
关闭socket:   closesocket()

-数据类型    struct sockaddr    {       
unsigned short  sa_family;   //地址族, 一般为AF_INET       
char                  sa_data[14];   //14字节的协议地址    }   

 struct sockaddr_in    {       
short int                     sin_family;   //地址族       
unsigned short int      sin_port;      //端口号      
 struct in_addr             in_addr;      //ip地址       
unsigned char             sin_zero[8];  //填充   
}
用socket函数传入地址时要注意字节序转换,每个机器的字节存储顺序不一样,但网络通信时需要统一标准,我们可以用
htons()---host to network short
htonl()---host to network long
ntohs() and ntohl reverse.

线程:
-创建(成功返回0,否则返回错误编号)
  int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
  tidp:线程标识符
  attr:线程属性设置
  start_rtn:线程函数起始地址
  arg:传递给start_rtn函数的参数
  

how create a TCP server:
1. create a socket and configure the IP address and port by struct -- socketaddr_in 
2. bind the IP and port
3. listen the signal, tell the client that server is ready to deal requests
4. build a link with requests from clients
5. put these requests into a listen queue and choose one to deal with by function accept()
6. for the request which is dealing  with, we can read and write ....



Saturday, 7 November 2015

Makefile小记(malloc project)

What a Rule Looks Like

target … : prerequisites …
        recipe

A target is usually the name of a file that is generated by a program; examples of targets are executable or object files. A target can also be the name of an action to carry out, such as ‘clean’ (see Phony Targets).
A prerequisite is a file that is used as input to create the target. A target often depends on several files.
A recipe is an action that make carries out.

target:目标文件
prerequites:前提条件,意思就是如果要执行目标文件下的recipe,prerequites的存在是必须条件。
recipe:即是shell的命令

Automatic Variables
These variables have values computed afresh for each rule that is executed, based on the target and prerequisites of the rule.In this example, you would use ‘$@’ for the object file name and ‘$<’ for the source file name.It’s very important that you recognize the limited scope in which automatic variable values are available: they only have values within the recipe. In particular, you cannot use them anywhere within the target list of a rule; they have no value there and will expand to the empty string. Also, they cannot be accessed directly within the prerequisite list of a rule.

ps:When it is time to execute recipes to update a target, they are executed by invoking a new sub-shell for each line of the recipe, unless the .ONESHELL special target is in effect (see Using One Shell) (In practice, make may take shortcuts that do not affect the results.)

//-------------------------------------------------------------------------------------------------------------------------------

接下来我修改了Makefile,使得它能通过编译main.c成二进制文件到tests/main,通过./main输出结果:

  1 CC=gcc
  2 CFLAGS =-std=c99 -pedantic -Wextra -Wall -Werror
  3 LDFLAGS=-shared -fPIC
  4 TARGET=libmalloc.so
  5 CHECK=check
  6 
  7 SRC= ./src/metadata.c  ./src/malloc.c \
  8       ./src/calloc.c
  9 OBJ=$(SRC=.c:.o)
告诉makefile把.c文件转为.o

 10 RM = rm -fr
 11 
 12 
 13 #target $@, object $^, first dependency file $<
 14 $(TARGET):$(OBJ)
 15   $(CC) $(LDFLAGS) -o $@ $(SRC)
编译libmalloc.so,首先所有的.o文件要存在

 16 
 17 main:
 18   #$(MAKE) -C test (意思:如果有子makefile在test文件夹里,命令一起执行)
 19   $(CC) $(CFLAGS) -o tests/main src/main.c 
单独编译main函数

 20 
 21 check:all
 22 all:$(TARGET) $(OBJ) main

 23   LD_PRELOAD=./libmalloc.so ./tests/main
LD_PRELOAD是把自己的库替换系统提供的库,使得文件用的是我自己同名的malloc

 24 .PHONY: clean
 25 clean:
 26   $(RM) $(OBJ) $(TARGET) \

 27   $(RM) a.out tests/main





http://blog.csdn.net/liang13664759/article/details/1771246
Makefile 全面讲解

http://ccckmit.wikidot.com/code:c0p
build parse tree实例

GNU make: Secondary Expansion

make rules 和 implicit rule search 


Monday, 2 November 2015

C process,fork() and execve()

1.fork()函数    作用:在一个进程下生成它的子进程。     当进程pid为0的时候代表当前进程为子进程,大于0则是父进程,小于0代表出错。     使用:     main()     {          pid_t fpid;          fpid=fork();     }
     在语句fpid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了.为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:    1)在父进程中,fork返回新创建子进程的进程ID;
    2)在子进程中,fork返回0;
    3)如果出现错误,fork返回一个负值;
     解释fpid的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其fpid为0.    fork出错可能有两种原因:    1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。    2)系统内存不足,这时errno的值被设置为ENOMEM。


  参考博客: http://blog.csdn.net/jason314/article/details/5640969




2.exec函数    作用:代码替换:根据文件名找到可执行文件,并用此文件来取代要调用的内容(shell脚本或者C文件)。通常是用fork()函数创建子进程后,子进程调用exec函数以执行另一个程序。   解释:当进程调用exec函数时,该进程完全有新程序代换,而新程序则从其main函数开始执行。 因为调用exec并不创建新进程,所以前后进程ID并不改变。只是用一个新程序替换了当前进程的征文,数据,堆和栈段。  exec其实是一个函数组,其中真正属于系统调用的函数只有   int execve(const char* path, char *const argv[], char *const envp[]);其余都是为了方便而设置的衍生的函数。 参数说明: 例如,我们要执行一个shell脚本文件,里面的执行代码为:cat /etc/passwd 通过which cat可知,cat的输出路径为bin/cat, *argv[]={"cat", "etc/passwd",NULL},*env[]={"PATH","bin","SHELL=bash",NULL},所以:execve("bin/cat",argv,env).(注意char型都以NULL结尾。)

Wednesday, 21 October 2015

C pointer comprehension

1、指针的初始化
初看起来,指针的初始化和赋值好像很混乱,又是*,又是&,时不时又出来一个数组。其实总结起来很简单:
int *p;
int a=25;
int b[10];
int *m=&a;
int *n=b;
int *r=&b[0];
指针的定义如上所示,以*打头的变量代表该变量为指针变量。
指针初始化时,“=”的右操作数必须为内存中数据的地址,不可以是变量,也不可以直接用整型地址值(但是int *p=0;除外,该语句表示指针为空)。此时,*p只是表示定义的是个指针变量,并没有间接取值的意思。
Int *s=15;
Int *s={2,3,5};
Int *s=a;
以上这三种初始化方式都是错误的。
2、指针的赋值
P=m;
P=&a;
P=b;
*p=25;
*p=a;
*p=b[4];
指针相关的赋值,“=”的左操作数可以是*p,也可以是p。
当“=”的左操作数是*p时,改变的是p所指向的地址存放的数据;当“=”的左操作数是p时,改变的是p所指向的地址。
数组的变量名b表示该数组的首地址,因此p=b;也是正确的。
3、   “特殊情况”
前面讲到了,指针的初始化必须使用变量地址,而不可以直接使用变量。
那么,下面这个又如何解释呢:
Char *cp=”abcd”;
其实,这个初始化过程,是将指针cp指向字符串的首地址,而并不是传递字符串的值。因为,在C语言里面,没有整体处理一个字符串的机制。
所以,我们的标题“特殊情况”加上了一个引号,因为,它实际上也是以变量地址初始化的指针,“特殊情况”并不特殊。
由此引出,如何使用字符串对指针赋值呢?只有采用下面这种方式:
Cp=”mnop”;
型如*cp=”mnop”;这样的语句是错误的。原因如上所述,字符串常量传递的是它的首地址。
另外,这个初始化过程还有另一层隐含的意思:”abcd”是字符串常量,在初始化过程中并没有发生字符串的复制,而只是简单的将指针指向该字符串常量,因此,不可以通过*cp修改该字符串的值,因为该字符串为常量。当然,我们可以使用“cp=”来修改指针指向的字符串,指针本身并不是常量。
如果试图通过指针*cp来修改该字符串,会出现什么结果,答案是未定义的,要视不同的编译器而定。至少有一点可以确定,在编译阶段,编译器不会报错,因为*cp不是常量,所以对*cp赋值并没有什么语法错误。但是有些编译器,比如VC,会在运行时抛出异常:写入位置 0x00415768(cp指向的地址) 时发生访问冲突!
这点上与char ca[]=”abcd”;是不同的,通过ca[x]可以修改字符串中的数据。


PS:
char* p =  malloc (sizeof(char) * BUFFER_SIZE);
 p[i] 和 *(p+i) 是一样的

Sunday, 18 October 2015

编译原理

重新来预习一下C语言文件的编译过程:
文件后缀变化: .c ==> .i ==> .s ==> *

*CPP是 预编译 的缩写 preprocess。*AST抽象语法树 abstract syntax tree.*SSA是”静态单赋值” static single assignment form。
*RTL是寄存器传输语言的缩写 register-transfer level.
1)首先将文件进行语法分析,通过token的方式得到对应语言的AST。
2)根据得到的AST生成中间代码并且优化。
3)根据目标机器的汇编描述,生成对应机器架构的汇编语言。
4)汇编器根据生成的汇编文件生成二进制文件供机器理解。
5)连接器ld将源码中调用的库函数连接进来。(-Iinclude的作用?)


下图是一个将一行代码编译为AST的过程的例子:(怎么翻译器那的二叉树和右边分析语言的不一样?)

参考http://blog.csdn.net/rill_zhen/article/details/7703557


至此,是基础。接下来是更详细更复杂的流程:
介绍:
编译器的工作的开始,就是读入源码(预编译先不考虑),然后,去除一些空字符,然后经过词素匹配,并和其属性(可选),组成一个的词法单元,多个词法单元,连接成词法单元序列。自此,词法分析器的工作就算完成了。
下面是词法分析器工作的内在机制图:

1)确定词素,就是读到字符串和模式匹配。
2)模式由DFA来匹配,DFA就是图(binary tree)。
3)图又可以由正则表达式表示。
4)正则表达式是通过语言文法产生式转换而来。
5)文法产生式,又是由编程语言本身来定义的。

参考博客:http://blog.csdn.net/rill_zhen/article/details/7722882

Thursday, 15 October 2015

File Descriptor

Je suis une formation de "File Descriptor"de JIKEXUEYUAN et j'ai écrit une programmation qui permet de faire copier coller depuis un fichier donné au autre fichier, ceci mes codes:


 Head File:
#ifndef   FILEIO_H
#define  FILEIO_H 
  void copy(int fd_in, int fd_out);  
#endif /*FILEIO_H*/

File filecopy.c#include "fileio.h"
#include <stdio.h>
#include <string.h>
#include <error.h>
#include <fcnlt.h>#include <unistd.h>#define BUFFER_LEN 1024
void copy(int fd_in, int fd_out) 
{    
char buffer[BUFFER_LEN] = {"\0"};    
ssize n ;
 while(n = read(fd_in, buffer, BUFFER_LEN) != 0)     
//read(int fd, char *buffer, size_t count) lire count bytes depuis le descripteur du fichier fd à partir *buffer.    
{        
if(n < 0)        
{            
fprintf(stderr, "read failed. %s\n", strerror(errno));             
//fprintf ici fonction sert à imprimer les infos d'erreur qui sont recuperées par  strerro(errno)        
} else if (n > 0)        
{            
if (write(fd_out, buffer, n) != n)        
 {          
    fprintf(stderr, "write failed. %s\n", strerror(errno));   
   }      
  }  
 } 
} 


File main 
#include "fileio.h"
#include <stdio.h>
#include <string.h>
#include <error.h>
#include <fcnlt.h>
#include <unistd.h>
int main(int argc, char *argv[2]) 
//argc est le nombre d'argument est ajouté dans la main fonction, argv est le contenu d'argument, ici, on va donner le chemin de fichier qui est copié et la destination de fichier copie. 
{  
if (argc < 3) 
//en fait, on transfert deux argument dans ce programme, mais dans ce cas il y a 3 argument, argc[0] est lui même.  
 {      
fprintf(stderr, "argument number error %s\n", strerror(errno) );   
 exit(1); //exit() est dans la bibliotheque de <stdlib.h>  
 }     
int fd_in = open(argv[1], O_RDONLY); 
// fd est définit ici par open      
if(fd_in < 0)    
  {          
fprintf(stderr, "open 1 failed. %s\n", strerror(errno) );       
exit(1);      
}  else { printf("open file %d\n", fd_in); } 

 int fd_out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644)     if(fd_out < 0)    
{          
fprintf(stderr, "open 2 failed. %s\n", strerror(errno) );         
exit(1);    
  }  else { printf("open file 2: %s\n")} 

copy(fd_in, fd_out);    
close(fd_in);  
close(fd_out); 
return 0;

}

Quand je complie ce programme, ceci les commendes que j'ai saisi:
mkdir bin // bin est un répertoire qui sert à mettre les fichiers temporaire, comme make
gcc -Iinclude mycp.c filecopy.c -o /bin/mycp //compiler
./bin/mycp /etc/passwd ./copypasswd.txt // transférer les arguments





Linux文件属性及系统结构

stat结构体
-Struct stat is a system call that returns files attributes about an inode. 

-Inode is a data structure used to represent a file system object, echo inode stores the attributes and disk block locations of the file system object's data.  And stat() return a file's  information in the inode and retrieves the file's inode number.

-Filesystem object attributes may include manipulation metadata (e.g. change,  access, modify time), as well as owner and permission data (e.g. group-id, user-id, permissions).
-Directories are lists of names assigned to inodes. The directory contains an entry for itself, its parent, and each of its children.
struct stat() is defined in <sys/stat.h> header file:
struct stat()
{
    mode_t    st_mode; /*file type & permission*/
    ino_t   st_ino; /*i-node number*/
    dev_t   st_dev /*device number*/
    nlink_t st_nlink /*number of links*/
    uid_t   st_uid /*user ID of owner -user id*/
    gid_t   st_gid /*group ID of owner*/
    off_t   st_size /*total size, in bytes unit*/
    time_t  st_atime /*time of last access*/
    time_t  st_mtime /*time of last modification*/
    ....
}


There are 9 types authority of visit a file(t_mode):
S_IRUSR, S_IWUSR, S_IXUSR
S_IRGRP, S_IWGRP, S_IXGRP
S_IROTH, S_IWOTH, S_IXOTH

We can use "t_mode  S_IXXXX" to juge the file, or we can use also the function "int access=(char *filepath, int mode)" to compare, if the result is positive,it return 0.

Let's understand how the system calculate the file's authority.
In Linux, the file's default authority is 666, and mask(掩码) is 
002 ==> 000 000 010(in binary) and we take the inverse number:
111 111 101 then it caculate 111 111 101 & 110 110 110 = 110 110 100 (664 in decimal)



File descriptor 文件描述符:
A file descriptor is an abstract indicator used to access a file or other input/output resource.
There three standard POSIX file descriptors, corresponding the three streams(define in head file <unistd.h>), which presumably every process should expect to have:
  1. 0 input STDIN_FILENO stdin
  2. 1 output STDOUT_FILENO stout
  3. 2 error STDERR_FILENO stderr