C第十天

第十课  编译预处理与大型程序
一、包含文件指令
编辑:hello.c,高级语言。
预处理(预编译):包含文件扩展、宏扩展等。
编译:汇编文件。
汇编:目标文件。
链接:可执行程序。
#include <stdio.h>
包含文件扩展:用被#include指令包含的文件内容替换该#include指令行。
#include<...>:从标准包含文件目录(/usr/include)找包含文件。常用于标准包含文件。
stdio.h
stdlib.h
string.h
stdbool.h
#include"...":首先找当前目录,没找到则取标准包含文件目录找,还没找到,根据-I选项指定的目录找。常用于自定义包含文件。
gcc -E可以查看预处理结果。
gcc -E xxx.c -o xxx.pc
二、宏定义指令
#define
1)常量宏
提高代码的可读性,可维护性。
#define 宏名 宏值
如:
#define PAI 3.14
预处理器将代码中出现的宏名全部替换为宏值。这个过程就叫做宏扩展或宏替换。
2)参数宏(宏函数)
#define 宏名(宏参数) 宏值
预处理器将宏参数替换为实际值后,代码中的宏名全部替换为宏值。
注意:小括号不要少。参数和被替换的宏值。
#define SQUARE(X) ((X)*(X))
3)语言扩展
4)#和##
#:表示将其后的宏参数作为字符串字面值进行替换。
##:表示将其后的宏参数替换以后与其前面的部分粘连在一起。
5)预定义宏
A.标准预定义宏
__FILE__:当前文件
__LINE__:当前行
__DATE__:编译日期
__TIME__:编译时间
__STDC__:是否支持标准C
B.编译器预定义宏
GNU编译器:__GNUC__
微软编译器:_MSC_VER
C.用户预定义宏
通过gcc的-D选项设置预定义宏。
如果宏是一个字符串的字面值,那么-D后面的宏值需要用\"引起来。
gcc -DVER=1.0
gcc -DCOPYRIGHT=\"达内科技\"
程序中的VER被宏替换为1.0,COPYRIGHT被宏替换为"达内科技"。
三、条件编译指令
#if // 如果,#if VER==1
#ifdef // 如果定义了...
#ifndef // 如果没有定义...
#elif // 否则如果...
#else // 否则
#endif // 和#if/#ifdef/#ifndef配对使用
#undef // 取消定义,和#define相反
满足条件(条件表达式的值非零)的代码参加编译,否则不参加编译。
四、头文件卫士
       com.h
       /  \
   net.h  des.h
    /  \  /  \
net.c  app.c des.c
头文件卫士:在xxx.h中
#ifndef _XXX_H
#define _XXX_H
// 头文件代码...
#endif // _XXX_H
防止同一个.h文件被沿着不同路径包含到一个.c文件中产生重定义冲突。
五、构建脚本
makefile三要素:
目标: 依赖
<制表符>规则,从依赖获得目标的方法
练习:实现安全版本的strcpy_s和strcat_s。
char* strcpy_s (
  char* dest, // 目标缓冲区
  size_t size, // 目标缓冲区的大小(最多容纳的字符个数)
  const char* src // 源字符串
);
char* strcat_s (
  char* dest,
  size_t size,
  const char* src
);
练习:实现字符串拆分函数:
void split (
  const char* psz, // 原始串
  const char* sep  // 分隔符
);
依次打印出原始串被分隔符分隔而成的各个子串。
split ("...192...168..1.2..", ".");
192
168
1
2
split ("minwei@tarena.com.cn",
"@.");
minwei
tarena
com
cn
最好支持中文。
split ("2012年8月10日", "年月日");
2012
8
10
#*.
###abc***xxx\0##*uiyt...
      ^
      2
   ^
   1


char* p = strchr ("hello", 'e');
p指向hello中的e字符
char* p = strchr ("hello", 'w');

p == NULL

#include "net.h"
#include "des.h"
int main (void){
  pack p;
  encrypt (&p);
  send (&p);
  recv (&p);
  decrypt (&p);
  printf ("呵呵...\n");
  return 0;
}

#include <stdio.h>
#include <string.h>
#define min(a,b) (((a)<(b))?(a):(b))
char* strcpy_s (char* dest, size_t size, const char* src) {
  if (dest && size && src) {
    size_t i, srclen = strlen (src);
    for (i = 0; i < min (size - 1, srclen); i++)
      dest[i] = src[i];
    dest[i] = '\0';
  }
  return dest;
}
char* strcat_s (char* dest, size_t size, const char* src) {
  if (dest && size && src) {
    size_t i, destlen = strlen (dest), srclen = strlen (src);
    for (i = destlen; i < min (size - 1, destlen + srclen); i++)
      dest[i] = src[i - destlen];
    dest[i] = '\0';
  }
  return dest;
}
#define SIZE(arr) sizeof(arr)/sizeof(arr[0])
int main (void) {
  int a = 0;
  char s[4];
  /* 不安全的strcpy/strcat
  strcpy (s, "abcd1234");
  printf ("%s\n", s); // abcd1234
  printf ("%x\n", a); // 34333231
  */
  strcpy_s (s, SIZE (s), "abcd1234");
  printf ("%s\n", s); // abc
  printf ("%x\n", a); // 0
  strcpy_s (s, SIZE (s), "ab");
  strcat_s (s, SIZE (s), "cd1234");
  printf ("%s\n", s); // abc
  printf ("%x\n", a); // 0
  return 0;
}

#include <stdio.h>
#include <string.h>
void split (const char* psz, const char* sep) {
  char sz[strlen (psz) + 1];
  strcpy (sz, psz);
  char *p1, *p2;
  for (p2 = sz; *p2; p2++) {
    for (; *p2 && strchr (sep, *p2); p2++);
    if (! *p2)
      break;
    p1 = p2;
    for (; *p2 && ! strchr (sep, *p2); p2++);
    if (! *p2) {
      puts (p1);
      break;
    }
    *p2 = '\0';
    puts (p1);
  }
}
int main (void) {
  char sz[1024], sep[128];
  gets (sz);
  gets (sep);
  split (sz, sep);
  return 0;
}

#include <stdio.h>
#define ISLEAP(y) ((y)%4==0&&(y)%100!=0||(y)%400==0)
#define ISSMALL(m) ((m)==4||(m)==6||(m)==9||(m)==11)
#define NORMAL(m) (ISSMALL(m)?30:31)
#define DAYS(y,m) ((m)==2?28+ISLEAP(y):NORMAL(m))
#define IN(x,f,t) ((x)>=f&&(x)<=t)
#define VALID(y,m,d) ((y)>0&&IN(m,1,12)&&IN(d,1,DAYS(y,m)))
int main (int argc, char* argv[]) {
  int y = atoi (argv[1]);
  int m = atoi (argv[2]);
  int d = atoi (argv[3]);
  printf ("%s日期。\n", VALID (y, m, d) ? "合法" : "非法");
  return 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值