数字时钟。

  这是以相关WIN API封装成控制台功能增强版函数库为基础,编写出的一个简单的时钟。

  此程序的目标是展示一点美感,比如结果上的、设计上的、代码格式上的。俗话说功夫在诗外,以美学为导向,为道,算是一种探索。

  不同领域中的不同的人对美的理解不一样,而且一般在多数时候无法言表,只能综合感受。在软件工程的表示层中美的共性定义有:简洁、精确、一致等等关键字。

  开始做了,首先以需求为导向,采用传统的面向过程设计,概括出这个程序的主体流程:先取得系统当前的细分时间,再通过光标定位、色彩控制和处理器延时,循环执行画出数字。

  因为想表现得更贴近在问题域上编程之意、体现简洁思想,所以统一地,提取了”数字时钟” 这个主题中的词汇,来概括整个程序的抽象层次,具体到命名及规范。

  然后在上面问题上进行合适地拆分。

  修饰细节后,最后表达出一个整体。

  系统中有些不易变的数据定义为宏,变成一套问题边界的参数,区分易变的部分,便于以后集中的修改控制,这里把它放在所有代码最上层,是为表示为所有过程共享,为工程级。

  如何画出一个数字?为了展示出C的底层知识的魅力,这个小程序的核心数据结构-表示数字方块形状的抽象表格(5×3的地图),用16位二进制位编码来映射表示,被压缩转换为十六进制存储。对此一维数组的操作算法,是个简单的位与运算的应用之一即判断指定位是否为1。

  这里数据驱动编程的运用,是这一模式的概念的狭义定义:把ifswitch这类结构化的等值判断的且较长的逻辑语句转换成数据表示,创建表结构,再设计出访问算法,隔离开变与不变的部分。

 

转载地址:

http://blog.csdn.net/blue123abc/article/details/8241749

 

代码如下:

  1. /* * * * * * * * * * * * * * * * * * * * * * * * 
  2. // Project: DigitalClock(数字时钟) 
  3. // Author: ProBlue 
  4. // Notes: Some functions about Win32 Console Control. 
  5. // Date:  2012.11.20 00:10 
  6.  * * * * * * * * * * * * * * * * * * * * * * * */  
  7.   
  8. #include <stdio.h>
      
  9. #include <stdlib.h>
      
  10. #include <time.h>
      
  11. #include “pcc32.h”
      
  12.   
  13. #define APP_TITLE   “数字时钟”
      
  14. #define APP_HEIGHT  7
      
  15. #define APP_WIDTH   38
      
  16. #define DIS_BASE_X  2
      
  17. #define DIS_BASE_Y  0
      
  18. #define TEXT_COLOR  LIGHT_GREEN
      
  19.   
  20. #define GotoMap(x,y) gotoTextPos((x)*2,(y))
      
  21. #define PRINT_BOX(s) printf(“%2s”,s)
      
  22. #define GET_BIT(v,b) ((v)>>(b)&1)
      
  23.   
  24. PCCOLOR COLORS[] = {BLACK, LIGHT_GREEN};  
  25. char  LIGHT[][3] = {” ““■”};  
  26.   
  27. // 各数字的形状方块的码表
      
  28. static uint16 digitTable[10] =  
  29. { 0x7B6F, 0x2492, 0x73E7, 0x79E7, 0x49ED, 0x79CF, 0x7BCF, 0x4927, 0x7BEF, 0x79EF };  
  30.   
  31. void drawDigit(int digit, int hx);  
  32. void drawSeptor(int color, int hx);  
  33. void initTime(int* hou, int* min, int* sec);  
  34. void delayMS(float secs);  
  35.   
  36. int main()  
  37. {  
  38.   int h,m,s;  
  39.   int sepcx = 0;  
  40.   
  41.   fixConsoleSize(APP_WIDTH*2, APP_HEIGHT);  
  42.   setConsoleTitle(APP_TITLE);  
  43.   setCursorVisible(0);  
  44.   initTime(&h, &m, &s);  
  45.   
  46.   while (1)  
  47.   {  
  48.     delayMS(0.97);  
  49.     drawSeptor(COLORS[sepcx = !sepcx], DIS_BASE_X + 22);  
  50.     drawSeptor(TEXT_COLOR, DIS_BASE_X + 10);  
  51.     drawDigit(h / 10, DIS_BASE_X + 0);  
  52.     drawDigit(h % 10, DIS_BASE_X + 4);  
  53.     drawDigit(m / 10, DIS_BASE_X + 12);  
  54.     drawDigit(m % 10, DIS_BASE_X + 16);  
  55.     drawDigit(s / 10, DIS_BASE_X + 24);  
  56.     drawDigit(s % 10, DIS_BASE_X + 28);  
  57.   
  58.     if (s >= 59)  
  59.     {  
  60.         ++m;  
  61.         s = 0;  
  62.     }  
  63.     else  
  64.         ++s;  
  65.     if (m >= 59)  
  66.     {  
  67.         ++h;  
  68.         m = 0;  
  69.     }  
  70.   }  
  71.   
  72.   return 0;  
  73. }  
  74.   
  75. void drawDigit(int digit, int hx)  
  76. {  
  77.   int b;  
  78.   int px = hx, py = DIS_BASE_Y;  
  79.   
  80.   setTextColor(TEXT_COLOR);  
  81.   for (b = 0; b <= 15; ++b)  
  82.   {  
  83.     GotoMap(px, py);  
  84.     PRINT_BOX(LIGHT[ GET_BIT(digitTable[digit], b-1) ]);  
  85.     if (b % 3 == 0)  
  86.     {  
  87.       py++;  
  88.       px = hx;  
  89.     }  
  90.     px++;  
  91.   }  
  92. }  
  93.   
  94. void drawSeptor(int color, int hx)  
  95. {  
  96.   setTextColor(color);  
  97.   GotoMap(hx, DIS_BASE_Y + 2);  
  98.   PRINT_BOX(LIGHT[1]);  
  99.   GotoMap(hx, DIS_BASE_Y + 4);  
  100.   PRINT_BOX(LIGHT[1]);  
  101. }  
  102.   
  103. void initTime(int* hou, int* min, int* sec)  
  104. {  
  105.   time_t t = time(NULL);  
  106.   struct tm* cur = localtime(&t);  
  107.   *hou = cur->tm_hour;  
  108.   *min = cur->tm_min;  
  109.   *sec = cur->tm_sec;  
  110. }  
  111.   
  112. void delayMS(float secs)  
  113. {  
  114.   clock_t start = clock();  
  115.   while (clock() – start < (secs * CLOCKS_PER_SEC))  
  116.     NULL;  
  117. }  
/* * * * * * * * * * * * * * * * * * * * * * * *
// Project: DigitalClock(数字时钟)
// Author: ProBlue
// Notes: Some functions about Win32 Console Control.
// Date:  2012.11.20 00:10
 * * * * * * * * * * * * * * * * * * * * * * * */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "pcc32.h"

#define APP_TITLE   "数字时钟"
#define APP_HEIGHT  7
#define APP_WIDTH   38
#define DIS_BASE_X  2
#define DIS_BASE_Y  0
#define TEXT_COLOR  LIGHT_GREEN

#define GotoMap(x,y) gotoTextPos((x)*2,(y))
#define PRINT_BOX(s) printf("%2s",s)
#define GET_BIT(v,b) ((v)>>(b)&1)

PCCOLOR COLORS[] = {BLACK, LIGHT_GREEN};
char  LIGHT[][3] = {" ", "■"};

// 各数字的形状方块的码表
static uint16 digitTable[10] =
{ 0x7B6F, 0x2492, 0x73E7, 0x79E7, 0x49ED, 0x79CF, 0x7BCF, 0x4927, 0x7BEF, 0x79EF };

void drawDigit(int digit, int hx);
void drawSeptor(int color, int hx);
void initTime(int* hou, int* min, int* sec);
void delayMS(float secs);

int main()
{
  int h,m,s;
  int sepcx = 0;

  fixConsoleSize(APP_WIDTH*2, APP_HEIGHT);
  setConsoleTitle(APP_TITLE);
  setCursorVisible(0);
  initTime(&h, &m, &s);

  while (1)
  {
    delayMS(0.97);
    drawSeptor(COLORS[sepcx = !sepcx], DIS_BASE_X + 22);
    drawSeptor(TEXT_COLOR, DIS_BASE_X + 10);
    drawDigit(h / 10, DIS_BASE_X + 0);
    drawDigit(h % 10, DIS_BASE_X + 4);
    drawDigit(m / 10, DIS_BASE_X + 12);
    drawDigit(m % 10, DIS_BASE_X + 16);
    drawDigit(s / 10, DIS_BASE_X + 24);
    drawDigit(s % 10, DIS_BASE_X + 28);

    if (s >= 59)
    {
        ++m;
        s = 0;
    }
    else
        ++s;
    if (m >= 59)
    {
        ++h;
        m = 0;
    }
  }

  return 0;
}

void drawDigit(int digit, int hx)
{
  int b;
  int px = hx, py = DIS_BASE_Y;

  setTextColor(TEXT_COLOR);
  for (b = 0; b <= 15; ++b)
  {
    GotoMap(px, py);
    PRINT_BOX(LIGHT[ GET_BIT(digitTable[digit], b-1) ]);
    if (b % 3 == 0)
    {
      py++;
      px = hx;
    }
    px++;
  }
}

void drawSeptor(int color, int hx)
{
  setTextColor(color);
  GotoMap(hx, DIS_BASE_Y + 2);
  PRINT_BOX(LIGHT[1]);
  GotoMap(hx, DIS_BASE_Y + 4);
  PRINT_BOX(LIGHT[1]);
}

void initTime(int* hou, int* min, int* sec)
{
  time_t t = time(NULL);
  struct tm* cur = localtime(&t);
  *hou = cur->tm_hour;
  *min = cur->tm_min;
  *sec = cur->tm_sec;
}

void delayMS(float secs)
{
  clock_t start = clock();
  while (clock() - start < (secs * CLOCKS_PER_SEC))
    NULL;
}


运行效果:

 

 

//pcc32 -About Win32 Console Control \’s Simple Library:

  1. #ifndef PCC32_H   
  2. #define PCC32_H   
  3.   
  4. #include <stdio.h>   
  5. #include <stdlib.h>   
  6. #include <conio.h>   
  7. #include <windows.h>   
  8.   
  9. typedef unsigned char uint8;  
  10. typedef unsigned short uint16;  
  11. typedef unsigned long uint32;  
  12.   
  13. /* 控制台尺寸定义 */  
  14. #define MIN_CONSOLE_WIDTH   14   
  15. #define MIN_CONSOLE_HEIGHT  1   
  16.   
  17. /* 颜色定义 */  
  18. typedef enum _PCCOLOR  
  19. {  
  20.    BLACK           =  0,   // 黑色   
  21.    BLUE            =  1,   // 蓝色   
  22.    GREEN           =  2,   // 绿色   
  23.    CYAN            =  3,   // 青色   
  24.    RED             =  4,   // 红色   
  25.    MAGENTA         =  5,   // 紫色   
  26.    BROWN           =  6,   // 褐色   
  27.    LIGHT_GRAY      =  7,   // 浅灰   
  28.    DARK_GRAY       =  8,   // 深灰   
  29.    LIGHT_BLUE      =  9,   // 亮蓝   
  30.    LIGHT_GREEN     = 10,   // 亮绿   
  31.    LIGHT_CYAN      = 11,   // 浅蓝   
  32.    LIGHT_RED       = 12,   // 亮红   
  33.    LIGHT_MAGENTA   = 13,   // 亮紫   
  34.    YELLOW          = 14,   // 黄色   
  35.    WHITE           = 15    // 白色   
  36. }PCCOLOR;  
  37.   
  38. #ifdef __cplusplus   
  39. extern “C”  
  40. {  
  41. #endif   
  42.   
  43.    /* 延时,以毫秒计 */  
  44.    void delay(uint32 d);  
  45.    /* 清除文字 */  
  46.    void clearText(void);  
  47.    /* 设置文本颜色,0~15 */  
  48.    int setTextColor(uint8 fColor);  
  49.    /* 屏幕光标定位,x为列(横),y为行(纵) */  
  50.    int gotoTextPos(uint8 x, uint8 y);  
  51.    /* 设置光标的可见性 */  
  52.    int setCursorVisible(int b);  
  53.    /* 设置控制台的标题字符串 */  
  54.    int setConsoleTitle(char *title);  
  55.    /* 设置一个没有滚动条的控制台窗口尺寸 */  
  56.    int fixConsoleSize(uint16 width, uint16 height);  
  57.    /* 输出控制台的相关信息(仅作调试用) */  
  58.    int showConsoleInfo();  
  59.   
  60. #ifdef __cplusplus   
  61. }  
  62. #endif   
  63.   
  64. #endif // PCC32_H  
#ifndef PCC32_H
#define PCC32_H

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

typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned long uint32;

/* 控制台尺寸定义 */
#define MIN_CONSOLE_WIDTH   14
#define MIN_CONSOLE_HEIGHT  1

/* 颜色定义 */
typedef enum _PCCOLOR
{
   BLACK           =  0,   // 黑色
   BLUE            =  1,   // 蓝色
   GREEN           =  2,   // 绿色
   CYAN            =  3,   // 青色
   RED             =  4,   // 红色
   MAGENTA         =  5,   // 紫色
   BROWN           =  6,   // 褐色
   LIGHT_GRAY      =  7,   // 浅灰
   DARK_GRAY       =  8,   // 深灰
   LIGHT_BLUE      =  9,   // 亮蓝
   LIGHT_GREEN     = 10,   // 亮绿
   LIGHT_CYAN      = 11,   // 浅蓝
   LIGHT_RED       = 12,   // 亮红
   LIGHT_MAGENTA   = 13,   // 亮紫
   YELLOW          = 14,   // 黄色
   WHITE           = 15    // 白色
}PCCOLOR;

#ifdef __cplusplus
extern "C"
{
#endif

   /* 延时,以毫秒计 */
   void delay(uint32 d);
   /* 清除文字 */
   void clearText(void);
   /* 设置文本颜色,0~15 */
   int setTextColor(uint8 fColor);
   /* 屏幕光标定位,x为列(横),y为行(纵) */
   int gotoTextPos(uint8 x, uint8 y);
   /* 设置光标的可见性 */
   int setCursorVisible(int b);
   /* 设置控制台的标题字符串 */
   int setConsoleTitle(char *title);
   /* 设置一个没有滚动条的控制台窗口尺寸 */
   int fixConsoleSize(uint16 width, uint16 height);
   /* 输出控制台的相关信息(仅作调试用) */
   int showConsoleInfo();

#ifdef __cplusplus
}
#endif

#endif // PCC32_H
  1. #include “pcc32.h”   
  2.   
  3. void delay(uint32 d)  
  4. {  
  5.   Sleep(d);  
  6.   return ;  
  7. }  
  8.   
  9. void clearText(void)  
  10. {  
  11.   system(“cls”);  
  12.   return ;  
  13. }  
  14.   
  15. int setTextColor(uint8 fColor)  
  16. {  
  17.   HANDLE hd = GetStdHandle(STD_OUTPUT_HANDLE);  
  18.   CONSOLE_SCREEN_BUFFER_INFO csbInfo;  
  19.   GetConsoleScreenBufferInfo(hd, &csbInfo);  
  20.   return SetConsoleTextAttribute(hd, fColor | (csbInfo.wAttributes&~0x0F));  
  21. }  
  22.   
  23. int gotoTextPos(uint8 x, uint8 y)  
  24. {  
  25.   COORD cd;  
  26.   cd.X = x;  
  27.   cd.Y = y;  
  28.   return SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cd);  
  29. }  
  30.   
  31. int setCursorVisible(int b)  
  32. {  
  33.   HANDLE hd = GetStdHandle(STD_OUTPUT_HANDLE);  
  34.   CONSOLE_CURSOR_INFO ccInfo;  
  35.   GetConsoleCursorInfo(hd, &ccInfo);  
  36.   ccInfo.bVisible = !!b;  
  37.   return SetConsoleCursorInfo(hd, &ccInfo);  
  38. }  
  39.   
  40. int setConsoleTitle(char *title)  
  41. {  
  42.   return SetConsoleTitle(title);  
  43. }  
  44.   
  45. int fixConsoleSize(uint16 width, uint16 height)  
  46. {  
  47.   int ret = 0;  
  48.   int fixX = 0, fixY = 0;  
  49.   COORD cd;  
  50.   SMALL_RECT srctWindow;  
  51.   CONSOLE_SCREEN_BUFFER_INFO csbiInfo;  
  52.   HANDLE hWin = GetStdHandle(STD_OUTPUT_HANDLE);  
  53.   
  54.   if (!hWin)  
  55.     return 0;  
  56.   
  57.   // 调整最小范围   
  58.   fixX = (width < MIN_CONSOLE_WIDTH) ? MIN_CONSOLE_WIDTH : width;  
  59.   fixY = (height < MIN_CONSOLE_HEIGHT) ? MIN_CONSOLE_HEIGHT : height;  
  60.   
  61.   // 先将BUF尺寸扩大到最大   
  62.   cd.X = 512;  
  63.   cd.Y = 512;  
  64.   ret = SetConsoleScreenBufferSize(hWin, cd);  
  65.   if (!ret)  
  66.     return ret;  
  67.   //puts(“Set Max Buf Error.”);   
  68.   
  69.   // 测试屏幕允许的最大尺寸   
  70.   GetConsoleScreenBufferInfo(hWin, &csbiInfo);  
  71.   cd = csbiInfo.dwMaximumWindowSize;  
  72.   //printf(“Max Win Size[%d, %d].\n”, cd.X, cd.Y);   
  73.   fixX = (fixX > cd.X) ? cd.X : fixX;  
  74.   fixY = (fixY > cd.Y) ? cd.Y : fixY;  
  75.   //printf(“Fix Win Size[%d, %d].\n”, fixX, fixY);   
  76.   
  77.   // 确定适当的窗口尺寸   
  78.   srctWindow.Left = 0;  
  79.   srctWindow.Right = fixX – 1;  
  80.   srctWindow.Top = 0;  
  81.   srctWindow.Bottom = fixY – 1;  
  82.   ret = SetConsoleWindowInfo(hWin, 1, &srctWindow);  
  83.   if (!ret)  
  84.     return ret;  
  85.   //puts(“Set Size Error.”);   
  86.   
  87.   // 确定适当的BUF尺寸   
  88.   cd.X = fixX;  
  89.   cd.Y = fixY;  
  90.   ret = SetConsoleScreenBufferSize(hWin, cd);  
  91.   if (!ret)  
  92.     return ret;  
  93.   
  94.   //printf(“Fix Win Size[%d, %d]: %d.\n”, fixX, fixY, ret);   
  95.   Sleep(100);  
  96.   return ret;  
  97. }  
  98.   
  99. int showConsoleInfo()  
  100. {  
  101.   int ret;  
  102.   HANDLE hWin = GetStdHandle(STD_OUTPUT_HANDLE);  
  103.   CONSOLE_SCREEN_BUFFER_INFO csbiInfo;  
  104.   
  105.   ret = GetConsoleScreenBufferInfo(hWin, &csbiInfo);  
  106.   if (ret)  
  107.   {  
  108.     printf(“Buffer Size: [X]%d – [Y]%d\n”, csbiInfo.dwSize.X, csbiInfo.dwSize.Y);  
  109.     printf(“Cursor Pos : [X]%d – [Y]%d\n”,  
  110.                csbiInfo.dwCursorPosition.X, csbiInfo.dwCursorPosition.Y);  
  111.     printf(“Attributes : %d\n”, csbiInfo.wAttributes);  
  112.     printf(“Current Win: [L]%d – [R]%d – [T]%d – [B]%d\n”, \  
  113.                csbiInfo.srWindow.Left, csbiInfo.srWindow.Right,  
  114.                    csbiInfo.srWindow.Top, csbiInfo.srWindow.Bottom);  
  115.     printf(“Maximum Win: [X]%d – [Y]%d\n”,  
  116.                csbiInfo.dwMaximumWindowSize.X, csbiInfo.dwMaximumWindowSize.Y);  
  117.     puts(“Over.”);  
  118.   }  
  119.   return ret;  
  120. }  
  121.   
  122. //End of pcc32.c  
#include "pcc32.h"

void delay(uint32 d)
{
  Sleep(d);
  return ;
}

void clearText(void)
{
  system("cls");
  return ;
}

int setTextColor(uint8 fColor)
{
  HANDLE hd = GetStdHandle(STD_OUTPUT_HANDLE);
  CONSOLE_SCREEN_BUFFER_INFO csbInfo;
  GetConsoleScreenBufferInfo(hd, &csbInfo);
  return SetConsoleTextAttribute(hd, fColor | (csbInfo.wAttributes&~0x0F));
}

int gotoTextPos(uint8 x, uint8 y)
{
  COORD cd;
  cd.X = x;
  cd.Y = y;
  return SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cd);
}

int setCursorVisible(int b)
{
  HANDLE hd = GetStdHandle(STD_OUTPUT_HANDLE);
  CONSOLE_CURSOR_INFO ccInfo;
  GetConsoleCursorInfo(hd, &ccInfo);
  ccInfo.bVisible = !!b;
  return SetConsoleCursorInfo(hd, &ccInfo);
}

int setConsoleTitle(char *title)
{
  return SetConsoleTitle(title);
}

int fixConsoleSize(uint16 width, uint16 height)
{
  int ret = 0;
  int fixX = 0, fixY = 0;
  COORD cd;
  SMALL_RECT srctWindow;
  CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
  HANDLE hWin = GetStdHandle(STD_OUTPUT_HANDLE);

  if (!hWin)
    return 0;

  // 调整最小范围
  fixX = (width < MIN_CONSOLE_WIDTH) ? MIN_CONSOLE_WIDTH : width;
  fixY = (height < MIN_CONSOLE_HEIGHT) ? MIN_CONSOLE_HEIGHT : height;

  // 先将BUF尺寸扩大到最大
  cd.X = 512;
  cd.Y = 512;
  ret = SetConsoleScreenBufferSize(hWin, cd);
  if (!ret)
    return ret;
  //puts("Set Max Buf Error.");

  // 测试屏幕允许的最大尺寸
  GetConsoleScreenBufferInfo(hWin, &csbiInfo);
  cd = csbiInfo.dwMaximumWindowSize;
  //printf("Max Win Size[%d, %d].\n", cd.X, cd.Y);
  fixX = (fixX > cd.X) ? cd.X : fixX;
  fixY = (fixY > cd.Y) ? cd.Y : fixY;
  //printf("Fix Win Size[%d, %d].\n", fixX, fixY);

  // 确定适当的窗口尺寸
  srctWindow.Left = 0;
  srctWindow.Right = fixX - 1;
  srctWindow.Top = 0;
  srctWindow.Bottom = fixY - 1;
  ret = SetConsoleWindowInfo(hWin, 1, &srctWindow);
  if (!ret)
    return ret;
  //puts("Set Size Error.");

  // 确定适当的BUF尺寸
  cd.X = fixX;
  cd.Y = fixY;
  ret = SetConsoleScreenBufferSize(hWin, cd);
  if (!ret)
    return ret;

  //printf("Fix Win Size[%d, %d]: %d.\n", fixX, fixY, ret);
  Sleep(100);
  return ret;
}

int showConsoleInfo()
{
  int ret;
  HANDLE hWin = GetStdHandle(STD_OUTPUT_HANDLE);
  CONSOLE_SCREEN_BUFFER_INFO csbiInfo;

  ret = GetConsoleScreenBufferInfo(hWin, &csbiInfo);
  if (ret)
  {
    printf("Buffer Size: [X]%d - [Y]%d\n", csbiInfo.dwSize.X, csbiInfo.dwSize.Y);
    printf("Cursor Pos : [X]%d - [Y]%d\n",
               csbiInfo.dwCursorPosition.X, csbiInfo.dwCursorPosition.Y);
    printf("Attributes : %d\n", csbiInfo.wAttributes);
    printf("Current Win: [L]%d - [R]%d - [T]%d - [B]%d\n", \
               csbiInfo.srWindow.Left, csbiInfo.srWindow.Right,
                   csbiInfo.srWindow.Top, csbiInfo.srWindow.Bottom);
    printf("Maximum Win: [X]%d - [Y]%d\n",
               csbiInfo.dwMaximumWindowSize.X, csbiInfo.dwMaximumWindowSize.Y);
    puts("Over.");
  }
  return ret;
}

//End of pcc32.c

版权声明:本文为onedime原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/onedime/archive/2012/12/31/2840947.html