UNIX Day03

1 返回非法值表示失败
2 返回空指针表示失败
3 返回-1表示失败
4 错误号和错误信息
5 不能根据错误号判断是否出错
6 内存映射的建立与解除
1 返回非法值表示失败
1.1 问题
如果一个函数的返回值存在确定的合法值域,那么就可以通过返回合法值域以外的值表示函数执行失败。

1.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:返回非法值表示失败

代码如下所示:

Long fsize (const char* path)
{
FILE* fp = fopen(path,”r”);
if(!fp)
return -13;
fseek(fp,0,SEEK_END);
long size = ftell(fp);
fclose(fp);
return size; }
上述代码中,以下代码:

if(!fp)
Return -13;
如果文件打开失败,则返回一个负数,因为合理的文件字节数不可能为负,负数在合理的数域之外表示失败。

1.3 完整代码
本案例的完整代码如下所示:

long fsize (const char* path)
{
FILE* fp = fopen(path,”r”);
if(!fp)
Return -13;
fseek(fp,0,SEEK_END);
long size = ftell(fp);
fclose(fp);
return size;
}
2 返回空指针表示失败
2.1 问题
如果一个函数的返回值是一个指针,那么就可以通过返回空指针(即值为0的指针,通常用NULL宏表示)表示函数执行失败。

2.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:返回空指针表示失败

代码如下所示:

const char* strmax (const char* a, const char* b)
{
return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;
}
上述代码中,以下代码:

return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;

当a、b中有一个为假时,返回NULL,表示无法比较两个字符串。

2.3 完整代码
本案例的完整代码如下所示:

const char* strmax (const char* a, const char* b)
{
return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;
}
3 返回-1表示失败
3.1 问题
返回0表示成功,返回-1表示失败,不输出数据或通过指针型参数输出数据。

3.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:返回-1表示失败

代码如下所示:

int mod (int a, int b, int* c)
{
if (b == 0)
return -1;
*c = a % b;
return 0;
}
上述代码中,以下代码:

 if (b == 0)
    return -1;

因为a对b求余数,余数可以是负数、零、正数,此时返回几都是合理范围内的值。此时就需要使用指针型参数c输出数据,而用0表示成功,返回-1表示失败。

3.3 完整代码
本案例的完整代码如下所示:

int mod (int a, int b, int* c)
{
if (b == 0)
return -1;
*c = a % b;
return 0;
}
4 错误号和错误信息
4.1 问题
系统预定义的整型全局变量errno中存储了最近一次系统调用的错误编号。该整数形式的错误号可以被转换为有意义的字符串。

4.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:错误号和错误信息

代码如下所示:

#include
#include
#include
#include
int main()
{
char* p = (char*)malloc (-1);
if (! p)
{
fprintf (stderr, “malloc: %s\n”, strerror (errno));
exit (EXIT_FAILURE);
}
scanf("%s", p);
printf("%s", p);
}
上述代码中,以下代码:

if (! p)
{
    fprintf (stderr, "malloc: %s\n", strerror (errno));
    exit (EXIT_FAILURE);
}

当申请内存失败后,系统预定义的整型全局变量errno中存储了错误编号。

注意:该编号必须包含errno.h头函数。

使用strerror函数可以将上述错误编号转为字符串。

注意:该函数必须包含string.h头函数。

4.3 完整代码
本案例中的完整代码如下所示:

#include
#include
#include
#include
int main()
{
char* p = (char*)malloc (-1);
if (! p)
{
fprintf (stderr, “malloc: %s\n”, strerror (errno));
exit (EXIT_FAILURE);
}
scanf("%s", p);
printf("%s", p);
}
5 不能根据错误号判断是否出错
5.1 问题
虽然所有的错误号都不是零,但是因为在函数执行成功的情况下错误号全局变量errno不会被修改,所以不能用该变量的值为零或非零,做为出错或没出错的判断依据。

5.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:错误做法

代码如下所示:

char* p = (char*)malloc (0xffffffff);
FILE* fp = fopen ("/etc/passwd", “r”);
if (errno)
fprintf (stderr, “无法打开口令文件!\n”);
上述代码中,以下代码:

if (errno)
不能直接使用错误号判断是否出错。

步骤二:正确做法

代码如下所示:

FILE* fp = fopen ("/etc/passwd", "r");
if(! fp)
    fprintf (stderr, "无法打开口令文件:%s\n", strerror (errno));

上述代码中,以下代码:

if(! fp)

先根据函数的返回值判断是否出错,在确定出错的前提下再根据errno的值判断具体出了什么错。

5.3 完整代码
本案例中的完整代码如下所示:

#include
#include
#include
int main()
{
/错误做法****
char* p = (char*)malloc (0xffffffff);
FILE* fp = fopen ("/etc/passwd", “r”);
if (errno)
fprintf (stderr, “无法打开口令文件!\n”);
正确做法**/
FILE* fp = fopen ("/etc/passwd", “r”);
if(! fp)
fprintf (stderr, “无法打开口令文件:%s\n”, strerror (errno));
fclose(fp);
}
6 内存映射的建立与解除
6.1 问题
所谓内存分配与释放,其本质就是建立或解除从虚拟内存到物理内存的映射,并在底层维护不同形式的数据结构,以把虚拟内存的占用与空闲情况记录下来。

6.2 步骤
实现此案例需要按照如下步骤进行。

步骤一:建立内存映射

代码如下所示:

#include
#include
#include
#include
int main()
{
char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (p == MAP_FAILED)
{
perror (“mmap”);
exit (EXIT_FAILURE);
}
strcpy (p, “Hello, Memory !”);
printf ("%s\n", p);

    return 0;

}
上述代码中,以下代码:

char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (p == MAP_FAILED)
{
    perror ("mmap");
    exit (EXIT_FAILURE);
}

使用mmap函数建立虚拟内存到物理内存或文件的映射。下面为函数形参的说明:

第一个形参为映射区内存起始地址,NULL系统自动选定后返回。

第二个形参为映射区字节长度,自动按页(4K)圆整。

第三个形参为映射区访问权限,可取以下值

PROT_READ - 映射区可读

PROT_WRITE - 映射区可写

PROT_EXEC - 映射区可执行

PROT_NONE - 映射区不可访问

第四个形参为映射标志,可取以下值

MAP_ANONYMOUS - 匿名映射,将虚拟内存映射到物理内存而非文件,忽略fd和offset参数

MAP_PRIVATE - 对映射区的写操作只反映到缓冲区中,并不会真正写入文件

MAP_SHARED - 对映射区的写操作直接反映到文件中

MAP_DENYWRITE - 拒绝其它对文件的写操作

MAP_FIXED - 若在start上无法创建映射,则失败(无此标志系统会自动调整)

MAP_LOCKED - 锁定映射区,保证其不被换出

第五个参数为文件描述符。

第六个参数为文件偏移量,自动按页(4K)对齐。

步骤二:解除内存映射

代码如下所示:

#include
#include
#include
#include
int main()
{
char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (p == MAP_FAILED)
{
perror (“mmap”);
exit (EXIT_FAILURE);
}
strcpy (p, “Hello, Memory !”);
printf ("%s\n", p);

if (munmap (p, 4096) == -1) 
{
    perror ("munmap");
    exit (EXIT_FAILURE);
}
strcpy (p += 4096, "Hello, Memory !");
printf ("%s\n", p);
if (munmap (p, 4096) == -1)
{
    perror ("munmap");
    exit (EXIT_FAILURE);
}
return 0;

}
上述代码中,以下代码:

if (munmap (p, 4096) == -1) 
{
    perror ("munmap");
    exit (EXIT_FAILURE);
}

使用munmap函数解除虚拟内存到物理内存或文件的映射。该函数的第一个形参为映射区内存起始地址,必须是页的首地址,第二个形参为映射区字节长度,自动按页(4K)圆整。munmap函数允许对映射区的一部分解映射,但必须按页。

6.3 完整代码
本案例的完整代码如下所示:

#include
#include
#include
#include
int main()
{
char* p = (char*)mmap (NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
if (p == MAP_FAILED)
{
perror (“mmap”);
exit (EXIT_FAILURE);
}
strcpy (p, “Hello, Memory !”);
printf ("%s\n", p);

if (munmap (p, 4096) == -1) 
{
    perror ("munmap");
    exit (EXIT_FAILURE);
}
strcpy (p += 4096, "Hello, Memory !");
printf ("%s\n", p);
if (munmap (p, 4096) == -1)
{
    perror ("munmap");
    exit (EXIT_FAILURE);
}
return 0;

}

你可能感兴趣的:(LINUX)