一个字符串没有字节怎么表示

一个字符串没有字节怎么表示,第1张

Jimmy1224

码龄11年

关注

字符是一种重要的数据类型,但是C语言并没有显式的字符串数据类型,因为字符串以字符串常量的形式出现或者存储于字符数组中。字符串常量适用于那些程序不会对它们进行修改的字符串。所有其他字符串都必须存储于字符数组或动态分配的内存中。本文描述处理字符串和字符的库函数,以及一些相关的,具有类似能力的,既可以处理字符串也可以处理非字符串数据的函数。

1.1 字符串基础

字符串是一串零个或多个字符,并且以一个位模式全0的NUL字节('\0')结尾。NUL字节是字符串的终止符,但它本身并不是字符串的一部分,所以字符串长度并不包括NUL字节。

头文件string.h包含了字符串函数所需的圆形和声明。在程序中包含这个头文件确实是个好主意,因为有了它所包含的原型,编译器可以更好地为程序执行错误检查。

1.2字符串长度

字符串的长度是它所包含的字符个数,不包含NUL字节。我们很容易对字符进行计数来计算字符串的长度。需要说明的是,如果strlen函数的参数不是一个以NUL字节结尾的字符序列,它将继续进行查找,直到发现一个NUL字节为止,这样strlen函数的返回值将是不确定数!

库函数strlen的源码如下:

size_t strlen(char const * string)

{

int length

for (length = 0*string++ != '\0')

{

length += 1

}

return length

}

注意:

strlen返回一个类型为size_t的值,它是一个无符号整数类型。在表达式中使用无符号可能导致不可预料的结果。

例如:

if ( strlen(x) >= strlen(y) )

{

...

}

if (strlen(x) - strlen(y) >= 0)

{

...

}

上面两个表达式看似相等,但事实上它们是不想等的。第一条语句是我们所预想的那样工作,但第2条语句的结果永远为真。因为strlen的结果是无符号,所以strlen(x)-strlen(y)的结果也是个无符号数,而无符号数都是大于等于“0”的。在表达式中如果同时包含了无符号和有符号数同样会产生奇怪的结果。

1.3 不受限制的字符串函数

最常用的字符串函数都是“不受限制”的,就是说它们只是通过寻找字符串参数结尾的NUL字节来判断它们的长度。这些函数一般都指定一块内存用于存放结果字符串。在使用这些函数时,程序员必须保证结果字符串不会溢出这块内存。

1.3.1 复制字符串

用于复制字符串的函数是strcpy,它的原型如下:

char *strcpy( char *dst, char const *src)

这个函数把参数src字符串复制到dst参数。如果参数src和dst在内存中出现重叠,其结果是未定义的。由于dst参数将进行修改,所以它必须是个字符数组或者是一个指向动态分配内存的数组指针,不能使用字符串常量。

目标参数以前的内容将被覆盖丢失。即使新的字符串比dst原先的内存更短,由于新的字符串是以NUL字节结尾,所以老字符串最后剩余的几个字符也会被有效地删除。需要注意的是字符结束标志也将被复制。

例如:

char message[] = "message"

...

if (...)

{

strcpy( message, "Dif")

}

如果条件为真并且复制顺利执行,数组将包含下面的内容:

第一个NUL字节后面的几个字符再也无法被字符串函数访问,因此从任何角度实现看,它们都已经是丢失的了。

注意:

程序员必须保证目标字符数组的空间足以容纳需要复制的字符串。如果字符串比数组长,多余的字符仍被复制,它们将覆盖原先存储于数组后面的内存空间的值。strcpy无法解决这个问题,因为它无法判断目标字符数组的长度。

1.3.2 连接字符串

strcat函数可以实现一个字符串添加到另一个字符串的后面。函数原型如下:

char *strcat( char *dst, char const *src)

strcat函数要求dst参数原先已经包含一个字符串(可以是空字符串)。它找到这个字符串的末尾,并把src字符串的一份拷贝添加到这个位置。如果src和dst的位置发生重叠,其结果是未定义的。

下面是这个函数的常见用法:

strcpy( message, "hello")

strcpy( message, customer_name)

注意:程序员必须保证目标字符数组剩余的空间足以保存整个src源字符串。

1.3.3 字符串比较

库函数strcmp的原型如下:

int strcmp( char const *s1, char const *s2)

字符串比较的规则:

对两个字符串自左向右逐个字符比较(按ASCII码值大小比较),直到出现不同的字符或遇到‘\0’为止,如果全部相同则认为相等。

1. s1小于s2,函数返回负整数;

2. s1大于s2,函数返回正整数;

3. s1等于s2,函数返回0;

注意:比较两个字符串更好的方法是把返回值与零进行比较。

if ( 0 == strcmp(str1,str2))

{

...

}

注意:

由于strcmp并不修改它的任一个参数,所以不存在溢出字符数组的危险。strcmp函数的字符串参数也必须以一个NUL字节结尾。如果不是,strcmp就可能对参数后面的字节进行比较,这个比较结果无意义!

1.4 长度受限的字符串函数

标准库函数还包含了一些函数,这些函数接受一个显式的长度参数,用于限定进行复制或比较的字符数。这些函数提供了一种方便的机制,可以防止难以预料的长字符串从它们的目标数组溢出。

这些函数的原型如下所示,和不受限制版本一样,如果源参数和目标参数发生重叠,strncpy和strncat的结果都是未定义。

char *strncpy(char *dst, char const *src, size_t len )

char *strncat(char *dst, char const *src, size_t len )

char *strncmp(char const *s1, char const *s2, size_t len )

1.4.1 strncpy

和strcpy一样,strncpy把源字符串的字符复制到目标数组。但它总是向dsr写入len个字符。如果strlen(src)的值小于len,dst数组就用额外的NUL字节填充到len长度。如果strlen(src)的值大于或等于len,那么只有len个字符被复制到dst中。此时,它的结果将可能不会以NUL字节结尾。

例如:

char dst[10]

char src[] = "abcdefghijklmn"

strncpy(dst, src,5)

//dst字符数组不是以NUL结尾,len是23,是个随机数

int len = strlen(dst)

警告:

strncpy调用的结果可能不是一个字符串,因此字符串必须是以NUL字节结尾。如果在一个需要字符串的地方(例如:strlen函数参数)使用了没有以NUL字节结尾的字符序列,会发生什么情况呢?strlen函数不知道NUL字节是没有的,所以它将继续一个字符一个字符的查找,知道发现NUL字节为止。或者如果函数试图访问系统分配给这个程序以外的内存范围,程序就会崩溃。

这个问题只有当你使用strncpy函数创建字符串,然后或者对它们使用str开头的库函数,或者在printf中使用%s格式打印它们时才会发生。考虑如下代码:

char buffer[BSIZE]

...

strncpy(buffer,name,BSIZE)

buffer[BSIZE-1] = '\0'

如果strlen(name)小于BSIZE,之后的赋值语句不起作用。但是,name长度很长,这条赋值语句可以保证buffer中的字符串是以NUL字节结尾。以后对这个数组使用strlen等其它函数就会正常工作。

1.4.2 strncat

strncat也是一个长度受限的函数,但它和strncpy不同,strncat从src中最多复制len个字符到目标数组的后面。并且,strncat总是在结果字符串后面添加一个NUL字节。它不管目标参数除去原先存在的字符串之后留下的空间够不够。

1.4.3 strncmp

strncmp用于比较两个字符串,但它最多比较len个字节。如果两个字符串在第len个字符之前存在不等的字符,这个函数停止比较,返回结果。如果两个字符串的前len个字符相等,函数就返回零。

1.5 字符串查找基础

标准库中存在许多函数,它们用各种不同的方法查找字符串。

1.5.1 查找一个字符

在一个字符串中查找一个特定字符最容易的方法是使用strchr和strchr函数,它们的原型如下:

char *strchr( char const *str, int ch)

char *strrchr( char const *str, int ch)

它们的第二个参数是一个整型值。但是,它包含了一个字符值(ASCII)。strchr在字符串中str查找字符ch第1次出现的位置,找到后函数返回一个指向该位置的指针。如果该字符并不存在于字符串中,函数就返回一个NUL指针。

strrchr的功能与strchr基本一致,只是它所返回的是一个指向字符串中该字符最后一次出现的位置(r:最右边)。

例如:

char src[] = "abc12def12"

printf("the first = %s\n",strchr(src,49))//strchr(src,'1')

1.5.2 查找任何几个字符

strprk是个更为常见的函数,它是查找任何一组字符第一次在字符串中出现的位置,它的原型如下:

char *strpbrk( char const *str, char const *group)

这个函数返回一个指向str中第1个匹配group中任何一个字符的字符位置。如果未找到函数返回一个NULL指针。

例如:

char src[] = "123qaz!@#"

char group[] = "aq!"

printf("location = %s\n",strpbrk(src,group))//qaz!@#,group中的字符第1次出现的位置是q

1.5.3 查找一个子串

为了在字符串中查找一个子串,我们可以使用strstr函数,它的原型如下:

char *strstr( char const *s1, char const *s2 )

这个函数在s1中查找整个s2第1次出现的位置,并返回一个指向该位置的指针。如果s2没有完整的出现在s1中任何地方,函数返回NULL指针。如果s2是一个空字符串,函数就返回s2。

1.6 高级字符串查找

1.6.1 查找一个字符串前缀

strspn和strcspn函数用于在字符串的起始位置对字符计数。它们的函数原型如下:

size_t strspn( char const *str, char const *group )

size_t strcspn( char const *str, char const *group )

1.6.2 查找标记

一个字符串常常包含几个单独的部分,它们彼此分隔开来。每次为了处理这些部分,你首先必须把它们从字符串中抽取出来。这个任务正是strtok函数所实现的功能。它从字符串中隔离各个单独的称为标记(token)的部分,并丢弃分割符。它的原型如下:

char *strtok( char *str, char const *sep)

sep参数是个字符串,定义了用作分隔符的字符集。str指定一个字符串,它包含零个或多个有sep字符串中一个或多个分隔符分隔的标记。strtok找到str的下一个标记,并将其用NUL结尾,然后返回一个指向这个标记的指针。

高级字符串查找将另外详解描述!

1.7 字符 *** 作

标准库包含了两组函数,用于 *** 作单独的字符,它们的原型位于头文件ctype.h。第一组函数用于字符分类,第二组函数用于转换字符。

1.7.1 字符分类

每个分类函数接受一个包含字符值的整型参数。函数测试这个字符并返回一个整型值,表示真或假。

int isalnum( int ch )

int iscntrl( int ch )

int islower( int ch )

int isprint( int ch )

int isupper( int ch )

int isspace( int ch )

1.7.2 字符转换

转换函数把大写字母转换为小写字母或把小写字母转换为大写字母。它们的函数原型如下:

int tolower( int ch )

int toupper( int ch )

toupper函数返回其参数的对应大写形式,tolower函数返回其参数的对应的小写形式。如果函数参数并不是处于一个适当的大小写的字符,函数将不修改直接返回。

提示:

直接测试或 *** 纵字符将会降低程序的可移植性。例如,考虑下面这条语句,它试图测试ch是否是一个大写字符。

if( ch >= 'A' &&ch <= 'z' )

这条语句在使用ASCII字符集的机器上能够运行,但是在使用EBCDIC字符集的机器上将会失败。另一方面,下面这条语句

if ( isupper( ch ) )

无论机器使用哪个字符集,它都能顺利进行,因此字符分类和转换函数可以提高函数的可移植性。

1.8 内存 *** 作

在非字符串数据中包含零值的情况并不罕见,此时无法使用字符串处理函数来处理这种类型的数据,因为当它们遇到第1个NUL字节时就停止工作。我们应该使用另外一组相关的函数,它们的 *** 作与字符串函数类似,但这些函数能够处理任意的字符序列。下面是它们的原型:

void *memcpy( void *dst, void const *src, size_t length )

void *memmvoe( void *dst, void const *src, size_t length )

void *memcmp( void const *a, void const *b, size_t length)

void *memchr( void const *a, int ch, size_t length)

void *memset( void *a, int ch, size_t length)

每个原型都包含一个显示的参数说明需要处理的字节数,它们在遇到NUL字节时并不会停止工作。

1.8.1 memcpy

void *memcpy( void *dst, void const *src, size_t length )

memcpy从src的起始位置复制length个字节到dst的内存起始位置,我们可以使用这种方法复制任何类型的值。第3个参数length指定了复制值的长度(以字节计)。如果src和dst以任何形式出现重叠,其结果都是未定义的。

例如:

char temp[SIZE],value[SIZE]

...

memcpy( temp, value, SIZE)//从数组value复制SIZE个字节到temp

如果两个数组为整型数组该怎么办?下面语句完成可以完成这项任务:

memcpy( temp, value, sizeof(value) )

memcpy()前两个参数类型是void*型指针,而任何类型的指针都可以转化为void*型指针。

1.8.2 memmove

void *memmvoe( void *dst, void const *src, size_t length )

memmove函数的行为和memcpy差不多,只是它的源和目标 *** 作数可以重叠。它的内部实现过程:把源 *** 作数复制到一个临时位置,这个临时的位置不会与源或目标 *** 作数重叠,然后再把它从这个临时位置复制到目标 *** 作数。如果源和目标参数真的可能存在重叠,就应该使用memmove,如下所示:

//Shift the values int the x array left one position.

memmove( x, x+1, ( count-1 ) * sizeof(x[0]) )

1.8.3 memcmp

void *memcmp( void const *a, void const *b, size_t length)

memcmp对两段内存的内容进行比较,这两段内存分别起始于a和b,共比较length个字节。这些值按照无符号字符逐字进行比较,函数的返回值与strcmp函数一样。由于这些值是根据一串无符号字节进行比较的,所以memcmp函数用于比较不是单字节的数据如整数或浮点数时可能出现不可预料的结果。

1.8.4 memchr

void *memchr( void const *a, int ch, size_t length)

memchr从a的起始位置开始查找字符ch第一次出现的位置,并返回一个指向该位置的指针,它共查找length个字节。如果在length个字节中未找到该字符,函数就返回NULL指针。

1.8.5 memset

void *memset( void *a, int ch, size_t length)

memset函数把从a开始的length字节都设置为字符值ch。例如:

memset( buffer, 0, SIZE)//把buffer前SIZE个字节都初始化为‘\0’

文章知识点与官方知识档案匹配

C技能树字符串字符串输入与输出

106612 人正在系统学习中

打开CSDN,阅读体验更佳

字符串、字符和字节

三者关系: 字符串是由一个个字符组成的,每个字符又由一个或多个字节来表示,每个字节又由8个bit位来表示。 字符:计算机中使用的文字和符号,比如1、2、A、B、%等等。 字节(Byte):一种计量单位,表示数据量多少,它是计算机信息技术用于计量存储容量的一种计量单位。 不同编码里,字符和字节的对应关系不同: ①ASCII码中,一个英文字母占一个字节的空间,一个中文汉字占两个字节的空间。 ②UTF-8编码中,一个英文字符等于一个字节,一个中文等于三个字节。 ③Unicode编码中,一个英文等于两个字节,一个中

继续访问

字符与字符串(新手,c语言)

字符与字符串,新手详细笔记,c语言

继续访问

最新发布 字符串(字节)长度计算

一般英文占一个长度,汉字占两个长度(字节),获取中英混合的字符串长度。

继续访问

热门推荐 字节,字符及占用内存大小情况

(一)“字节”的定义 字节(Byte)是一种计量单位,表示数据量多少,它是计算机信息技术用于计量存储容量的一种计量单位。 (二)“字符”的定义 字符是指计算机中使用的文字和符号,比如1、2、3、A、B、C、~!·#¥%……—*()——+、等等。 (三)“字节”与“字符” 它们完全不是一个位面的概念,所以两者之间没有“区别”这个说法。不同编码里,字符和字节的对应关系不同:

继续访问

c语言字符串长度,占用字节大小,存放位置等问题

参考文章:https://www.cnblogs.com/xmhsincere/p/4915354.html 1、三者长度strlen问题 int main () { char *str="xiaolong"printf("%d\n",strlen(str))return 0} 结果: #include <stdio.h>#include <string.h>int main ...

继续访问

Linux 中与字符串相关的函数strpbrk、strcasecmp、strspn(不间断更新)

本篇博客旨在整理出所有Linux网络编程中常用的字符串相关的函数,这些函数普遍用在处理网络通信中的字符串数据。话不多说,直接进入正题。 1、strpbrk函数 #include<string.h>char* strpbrk(char* s1, char* s2)strpbrk()从第一个字符指针指向的位置 向后检查每个字符,直到遇到\0(不检查\0),如果检查到的某个字符在s2指向的字符串中,那么返回他的地址,并停止检查。 如果s1 、s2没有相同字符,返回NULL。 注:传入strpb

继续访问

Linux下对字符串处理的实现函数(一)

1.Linux下字符串大小写转换 2.Linux下删除字符串中对应标志字符串的首字符串 3.Linux下删除字符串中不需要的空格(示例:逗号前后) 5.Linux下处理字符串——忽略双引号内容 6.Linux下字符串分割——忽略双引号内容.........

继续访问

linux 纯字符串,Linux下常用的字符串函数

13. strlen()(返回字符串长度)相关函数表头文件 #include定义函数 size_t strlen (const char *s)函数说明 strlen()用来计算指定的字符串s的长度,不包括结束字符"\0"。返回值 返回字符串s的字符数。范例#includemain(){char *str = "12345678"printf("str length = %d\n"...

继续访问

linux 字符串 *** 作函数

1 strchr 函数原型:extern char *strchr(char *str,char character) 参数说明:str为一个字符串的指针,character为一个待查找字符。 所在库名:#include <string.h> 函数功能:从字符串str中寻找字符character第一次出现的位置。返回说明:返回指向第一次出现字符cha...

继续访问

linux下字符串 *** 作,Linux shell 字符串 *** 作详解-Fun言

1、Linux shell 截取字符变量的前8位实现方法有如下几种:expr substr “$a” 1 8echo $a|awk ‘{print substr(,1,8)}’echo $a|cut -c1-8echo $expr $a : ‘\(.\\).*’echo $a|dd bs=1 count=8 2>/dev/null2、按指定的字符串截取(1)第一种方法:从左向右截取最后一个s...

继续访问

Linux *** 作字符串

目录 获取字符串长度: 提取子字符串: 子字符串消除 字符串替换 子字符串所在位置 获取字符串长度: 从字符串开始的地方匹配子字符串的长度: 1.expr match "$string" '$substring' 2.expr "$string" : '$substring 注释:$substring是一个正则表达式 提取子字符串: 1.${string:position} 在string 中从位置$position 开始提取子字符串. 如果$string为"*"或"@",

继续访问

Linux字符串 *** 作

Linux字符串 *** 作 描述 shell内置一系列的 *** 作符合,可以对字符串进行 *** 作; 常用 *** 作 表达式 含义 ${#string} $string的长度 ${string:position} 在string中从位置position开始提取子串 ${string:position:length} 在string中从位置position开始提取长度为$length的子串 ${string#substring} 从变量string的开头删除最短匹配substring的子串 ${s

继续访问

linux 字符串比较、数值比较

字符串相等: [[ $str1 == $str2 ]] 字符串不相等: [[ $str1 != $str2 ]] 字符串大小比较: [[ $str1 >$str2 ]] 字符串等于空: [[ -z $str2 ]] 字符串不等于空: [[ -n $str2 ]] 二元比较 *** 作符,比较变量或者比较数字.注意数字与字符串的区别. 整数比较 -eq 等于,如:if [ "$a" -eq "$b" ] -ne

继续访问

Linux下常用的字符串函数合集分享

转自:Linux下常用的字符串函数一、字符间的转换1 tolower(将大写字母转换成小写字母)相关函数isalpha,toupper表头文件 include定义函数int tolower(int c)函数说明。。。https://www.pinlue.com/article/2019/04/1316/558651446754.html ...

继续访问

字符串(Linux应用编程篇)

关于字符串的相关 *** 作有 输入、输出、合并、修改、比较、转换、复制、搜索等等 一、字符串I/O 宏定义文件指针:标准输入设备stdin、标准输出设备stdout、标准错误设备stderr 字符串输出 putchar()、puts()、fputc()、fputs()这些函数也是标准 I/O 函数,标准C库函数,且应层的函数是有缓冲的,性能和效率要比系统调用要高。 /* @ puts函数 @ 头文件:#include <stdio.h>@ s:需要进行输出的字符串 @ 返回值:成功返回一

继续访问

Linux下的基本C编程的三类高频函数 *** 作第二类——字符串 *** 作函数(str)

一,strlen和sizeof strlen一般用来求字符串长度,而sizeof是求这一段储存空间的大小。它们的区别在于strlen不计算空白符的大小,且遇到\0就会停止工作。 例如 #include <stdio.h>#include <string.h>int main(int argc, char **argv) { printf("%ld\n",strlen("hello baby"))//结果为10; printf("%ld

继续访问

linux shell 函数返回字符串,如何从Bash函数返回字符串值

您可以让函数将变量作为第一个arg,然后使用要返回的字符串修改变量。#!/bin/bashset -xfunction pass_back_a_string() {eval "$1='foo bar rab oof'"}return_var=''pass_back_a_string return_varecho $return_var打印“ foo bar rab oof”。编辑:在适当的位置添加...

继续访问

字符串长度与字节个数

在纯ASCII码下,字节数=字符串长度=字符个数,因为每个字符就一个字节。 在Unicode下,字节数/2=字符串长度=字符个数,因为每个字符都是2个字节。 在ASCII码与其它双字节字符系统混用时,字节数=ASCII码字符个数+双字节字符个数*2,而此时字符串长度到底怎么统计就不好说了,有的语言如C语言,此时字符串长度=字节数,有的语言如JS,此时字符产长度=字符个数。

继续访问

Linux 常用C函数(内存及字符串 *** 作篇2)

Linux 常用C函数(内存及字符串 *** 作篇2)2007-03-22 11:36 strcat(连接两字符串)

继续访问

c

c++

字符串处理

写评论

评论

1

博客园首页联系管理

jiffies相关时间比较函数time_after、time_before详解

1. jiffies简介

首先, *** 作系统有个系统专用定时器(system timer),俗称滴答定时器,或者系统心跳。

全局变量jiffies取值为自 *** 作系统启动以来的时钟滴答的数目,数据类型为 unsigned long volatile (32位无符号长整型),最大取值是2^32-1。

2. jiffies与秒的转换

将 jiffies转换为秒,可采用公式:(jiffies/HZ) 计算。

将 秒转换为jiffies,可采用公式:(seconds*HZ) 计算。

示例(本博客后面将介绍涉及到的time_before):

unsgned long delay = jiffies + 2*HZ

while(time_before(jiffies, delay))// 忙等待两秒,占用CPU的一个核心,期间不执行调度

3. jiffies的溢出介绍

当时钟中断发生时,jiffies值就加1。

假定HZ=100,那么1个jiffies等于1/100 秒,jiffies可记录的最大秒数为(2^32 -1)/100=42949672.95秒,约合497天或1.38年,

当取值到达最大值时仍继续加1,就变为了0!

即HZ=100时,连续累加的溢出时间是一年又四个多月,如果程序对jiffies的溢出没有加以充分考虑,那么在连续运行一年又四个多月后,这些程序还能够稳定运行吗?

4. 示例1,一个 jiffies溢出造成程序逻辑出错 的示例

复制代码

unsigned long timeout = jiffies + HZ/2/* timeout in 0.5s */

/* do some work ... */

do_somework()

/* then see whether we took too long */

if (timeout >jiffies) {

/* we did not time out, call no_timeout_handler() ... */

no_timeout_handler()

} else {

/* we timed out, call timeout_handler() ... */

timeout_handler()

}

复制代码

本例的意图:

从当前时间起,如果在0.5秒内执行完do_somework(),则调用no_timeout_handler()。如果在0.5秒后执行完do_somework(),则调用timeout_handler()。

然后当溢出时呢? 该意图会被打破吗?

假设程序开始执行前,timeout值已经接近最大值(即2^32-1 ) ,jiffies的值是(timeout-HZ/2),

之后do_some_work执行了挺久(超过0.5秒),jiffies的值也发生了溢出(jiffies做自增 *** 作的中途超过了32位无符号数的最大值),

溢出后的值,可能是很小的一个数字,所以造成jiffies的值 <timeout,

之后的代码执行流就走到了no_time_handler()这里,这显然和程序设计者的初衷(意图)是违背的。

5. Linux内核如何来防止jiffies溢出

Linux内核中提供了一些宏,可有效地解决由于jiffies溢出而造成程序逻辑出错的情况。

PS:下图源自Linux Kernel version 3.10.14

* time_after:

* time_after(a,b) returns true if the time a is after time b.

同时根据 #define time_before(a,b)time_after(b,a) ,我们可以知道

* time_before(a,b) returns true if the time b is after time a.

6. time_after 在驱动代码中的应用展示

7. time_after等用于时间比较的宏的原理简介

下面的文字摘录自博文:https://blog.csdn.net/jk110333/article/details/8177285

读者先大致浏览一遍即可,不必纠结于绞尽脑汁的细节理解, 后面我将表达个人理解,读者也可以直接向下浏览,看我的个人理解。

/**********************************开始摘录********************************************/

 我们仍然以8位无符号整型(unsigned char)为例来加以说明。仿照上面的time_after宏,我们可以给出简化的8位无符号整型对应的after宏:

 #define uc_after(a, b) ((char)(b) - (char)(a) <0)

设a和b的数据类型为unsigned char,b为临近8位无符号整型最大值附近的一个固定值254,下面给出随着a(设其初始值为254)变化而得到的计算值:

a b (char)(b) - (char)(a)

254 254 0

255 - 1

0 - 2

1 - 3

...

124 -126

125 -127

126 -128

127 127

128 126

...

252 2

253 1

 从上面的计算可以看出,设定b不变,随着a(设其初始值为254)不断增长1,a的取值变化为:

254, 255, (一次产生溢出)

0, 1, ..., 124, 125, 126, 127, 126, ..., 253, 254, 255, (二次产生溢出)

0, 1, ...

...

而(char)(b) - (char)(a)的变化为:

0, -1,

-2, -3, ..., -126, -127, -128, 127, 126, ..., 1, 0, -1,

-2, -3, ...

...

从上面的详细过程可以看出,当a取值为254,255, 接着在(一次产生溢出)之后变为0,然后增长到127之前,uc_after(a,b)的结果都显示a是在b之后,这也与我们的预期相符。但在a取值为 127之后, uc_after(a,b)的结果却显示a是在b之前。

从上面的运算过程可以得出以下结论:

使用uc_after(a,b)宏来计算两个8位无符号整型a和b之间的大小(或先/后,before/after),那么a和b的取值应当满足以下限定条件:

. 两个值之间相差从逻辑值来讲应小于有符号整型的最大值。

. 对于8位无符号整型,两个值之间相差从逻辑值来讲应小于128。

从上面可以类推出以下结论:

对于time_after等比较jiffies先/后的宏,两个值的取值应当满足以下限定条件:

两个值之间相差从逻辑值来讲应小于有符号整型的最大值。

对于32位无符号整型,两个值之间相差从逻辑值来讲应小于2147483647。

对于HZ=100,那么两个时间值之间相差不应当超过2147483647/100秒 = 0.69年 = 248.5天。

对于HZ=60,那么两个时间值之间相差不应当超过2147483647/60秒 = 1.135年。

在实际代码应用中,需要比较的先/后的两个时间值之间一般都相差很小,范围大致在1秒~1天左右,所以以上time_after等比较时间先 /后的宏完全可以放心地用于实际的代码中。 

/***********************************摘录结束******************************************/

看完这段文字,感觉有点绕的,那么原理到底是啥呢? 是一堆数学计算吗?是啊 ,就是这数学规律!

凡事都是有利有弊的,针对一件事物的优化,有利处,必然带来不利之处,从哲学角度来进行理解,事物的两面性。

本文第4部分,示例1介绍了jiffies的一个例子,它的弊处是会溢出,如果我们不抓住溢出这个弊处来看待这件事物,那么timeout的值可以做的很大,这是优势。

然而溢出是真实存在的,无法满足客观需求的,所以需要改进,

从该数学规律入手进行改进后,不溢出了,这是优势,

但是改进后对timeout的值也缩小了使用范围,这是为了达到该优势所带来的必要开销或损耗。这就是事物的两面性。

8. 示例2,对示例1进行改进:使用time_before宏后的正确代码

复制代码

unsigned long timeout = jiffies + HZ/2/* timeout in 0.5s */

/* do some work ... */

do_somework()

/* then see whether we took too long */

if (time_before(jiffies, timeout)) {

/* we did not time out, call no_timeout_handler() ... */

no_timeout_handler()

} else {

/* we timed out, call timeout_handler() ... */

timeout_handler()

}

复制代码

.

/************* 社会的有色眼光是:博士生、研究生、本科生、车间工人重点大学高材生、普通院校、二流院校、野鸡大学年薪百万、五十万、五万这些都只是帽子,可以失败千百次,但我和社会都觉得,人只要成功一次,就能换一顶帽子,只是社会看不见你之前的失败的帽子。 当然,换帽子决不是最终目的,走好自己的路就行。 杭州.大话西游 *******/

分类: Linux驱动

标签: 内核编程

好文要顶 关注我 收藏该文

一匹夫

粉丝 - 28 关注 - 3

+加关注

00

« 上一篇: 为什么我觉得需要熟悉vim使用,难道仅仅是为了耍酷?

» 下一篇: 九鼎S5PV210开发板的SD卡启动、uboot tftp升级内核镜像

posted @ 2021-01-30 14:39 一匹夫 阅读(2508) 评论(0) 编辑 收藏 举报

刷新评论刷新页面返回顶部

登录后才能查看或发表评论,立即 登录 或者 逛逛 博客园首页

【推荐】阿里云新人特惠,爆款云服务器2核4G低至0.46元/天

编辑推荐:

· .Net 6 使用 Consul 实现服务注册与发现

· SQLSERVER 的复合索引和包含索引到底有啥区别?

· [ASP.NET Core] 按用户等级授权

· 深入理解 Linux 物理内存分配全链路实现

· 巧用视觉障眼法,还原 3D 文字特效

阅读排行:

· 既然有MySQL了,为什么还要有MongoDB?

· C#开发的插件程序 - 开源研究系列文章

· 2022年工作总结,迟到比没到好

· 20 张图带你全面了解 HTTPS 协议,再也不怕面试问到了!

· .net core *** 作MongoDB

公告

音乐2 - 林海

00:00 / 00:00An audio error has occurred, player will skip forward in 2 seconds.

1 音乐1Valentin

2 音乐2林海

3 音乐3赵海洋

昵称: 一匹夫

园龄: 5年9个月

粉丝: 28

关注: 3

+加关注

< 2023年1月 >

日 一 二 三 四 五 六

1 2 3 4 5 6 7

8 9 10 11 12 13 14

15 16 17 18 19 20 21

22 23 24 25 26 27 28

29 30 31 1 2 3 4

5 6 7 8 9 10 11

搜索

找找看

谷歌搜索

常用链接

我的随笔

我的评论

我的参与

最新评论

我的标签

我的标签

linux(24)

系统编程(21)

C++(16)

BOOST(10)

ffmpeg(7)

更多

随笔分类

C++之QT(4)

C++之STL、Boost(12)

C++之语言与时俱进(17)

C语言活用(9)

C语言自身(12)

GUI(3)

Linux驱动(8)

Linux系统编程(32)

Linux应用(13)

MCU和物联网等(20)

RTOS(10)

shell 和 makefile(9)

uboot(3)

编程思维技巧(5)

编译器特性(2)

*** 作系统(2)

电路-EDA设计(2)

电路-基础知识(2)

调试篇(3)

汇编(1)

密码学|安全|(2)

配置相关(8)

嵌入式外设相关(2)

设计模式(12)

数据结构(3)

网络(13)

我的程序人生(1)

音视频(10)

随笔档案

2022年2月(3)

2022年1月(1)

2021年12月(5)

2021年11月(2)

2021年10月(1)

2021年8月(1)

2021年7月(2)

2021年5月(1)

2021年4月(6)

2021年3月(6)

2021年2月(6)

2021年1月(23)

2020年12月(11)

2020年11月(4)

2020年10月(29)

2020年9月(12)

2020年8月(12)

2020年5月(4)

2020年2月(6)

2020年1月(4)

2019年12月(2)

2019年11月(2)

2019年10月(3)

2019年8月(9)

2019年7月(2)

2019年6月(1)

2019年5月(1)

2019年4月(2)

2019年3月(5)

2019年2月(11)

2019年1月(6)

2018年1月(2)

2017年5月(1)

相册

大话西游经典照片(1)

阅读排行榜

1. C++函数默认参数 详解(29043)

2. 玩转Libmodbus(一) 搭建开发环境(16605)

3. 玩转Libmodbus(二) 写代码体验(7565)

4. RTThread DFS文件系统使用: 基于使用SFUD驱动的SPI FLASH之上的ELM FATFS文件系统(4537)

5. std(标准库)和STL(标准模板库)的关系(4149)

6. STM32CubeMX HAL库串口: 使用DMA数据发送、使用DMA不定长度数据接收(4016)

7. Arduino+ESP32 之 SD卡读写(3673)

8. KEIL查看ARM-Cortex M架构soc的内核寄存器之 MSP(3668)

9. 图解MQTT概念、mosquitto编译和部署 ,写代码,分别使用外网和本地服务器进行测试(3275)

10. RT Thread的SPI设备驱动框架的使用以及内部机制分析(2787)

11. STM32的CCM RAM以及使用方式(2540)

12. vscode废掉了,跳转不到函数定义,无法自动补全,重装也没用的解决办法(2511)

13. jiffies相关时间比较函数time_after、time_before详解(2508)

14. Arduino+ESP32 之 驱动GC9A01圆形LCD(一),基于Arduino_GFX库(2504)

15. 图解连接阿里云(一)创建阿里云物联网平台产品和设备,使用MQTT.fx快速体验(2372)

16. MDK内的KEEP关键字以及$$Base $$Limit(2358)

17. RT Thread SPI设备 使用(2246)

18. ESP32的Linux开发环境搭建,将示例程序编译、下载、运行(2243)

19. AD设置过孔盖油和过孔开窗, 过孔塞油科普(2186)

20. Linux 串口工具 lsz lrz 移植(2172)

评论排行榜

1. 在KEIL下查看单片机编程内存使用情况(2)

2. 玩转Libmodbus(一) 搭建开发环境(2)

3. C语言普通写法实现:针对多次同步失败的节能处理机制(2)

推荐排行榜

1. C++函数默认参数 详解(5)

2. 如何更好地谋生,从事嵌入式软件开发五年的感悟和职业焦虑(4)

3. Arduino+ESP32 之 SD卡读写(2)

4. 玩转Libmodbus(一) 搭建开发环境(2)

5. Arduino+ESP32 之 驱动GC9A01圆形LCD(一),基于Arduino_GFX库(1)

最新评论

1. Re:在KEIL下查看单片机编程内存使用情况

@HQ_嗨海 谢谢...

--一匹夫

2. Re:如何更好地谋生,从事嵌入式软件开发五年的感悟和职业焦虑

说的不错

--Chance_21_12_12

3. Re:在KEIL下查看单片机编程内存使用情况

感谢大佬

--HQ_嗨海

Copyright © 2023 一匹夫

Powered by .NET 7.0 on Kubernetes

第一个:鸟哥的 Linux 私房菜 -- 鸟哥的 Linux 私房菜 首页

博客介绍:大名鼎鼎的Linux私房菜,放在第一个位置毋庸置疑。如果你想要系统的学习Linux这儿会是你得不二选择。鸟哥是何许人也?鸟哥的 Linux 私房菜 -- 关於鸟哥

博客目录摘要(更多精彩内容请进博客):

新手建议:Linux 新鲜人必看

开始阅读之前:鸟哥这个网站的字体与风格编排之意义

网站导览:就是您目前看的这个网页

Linux 基础文件:一些很基础的文件汇整

Linux 架站文件:架站文件的汇整

Linux 安全管理:主机主体与网路安全的文件汇整H(施工中)

Apache 套件安装:关於各种 Apache 上面执行的套件的安装!

ADSL 频宽分享相关文件:主要利用不止是 Linux 的频宽分享!

第二个:Linux - 标签

博主介绍:Vamei,一名编程爱好者熟悉Python/Linux/网络协议/算法/Java/数据科学系列

博客介绍:如果你正在想学习Linux,你完全没有基础,那么这个博客正适合你。通读几篇文章练习练习一些基本的命令,不要再犹豫了,马上就动手吧。

博客目录摘要:

为什么要学习Linux

Linux文件系统的实现

Linux常用命令

Linux进程间通信

Linux多线程与同步

Linux从程序到进程

Linux用户与“最小权限”原则

Linux进程关系

Linux信号基础

Linux进程基础

Linux架构 - Vamei

Linux文本流 - Vamei

Linux文件管理相关命令

Linux命令行与命令

Linux文件管理

Linux开机启动(bootstrap)

Linux简介与厂商版本

第三个:Linux大棚 – 不忘初心的技术博客,浮躁时代的安静角落

博客介绍:写了八年的博客、关于Linux关于Linux C。正如标题:不忘初心、浮躁时代的安静角落。用一个月用两个月去学习阅读一遍别人的八年、何尝不是一种享受。学习前辈的经验、学习别人总结的内容。

博客目录摘要(更多精彩内容请进博客):

《service》-“linux命令五分钟系列”之二

《du命令》-linux命令五分钟系列之三

《chkconfig命令》

《uname命令》

《tr命令》-linux命令五分钟系列之六

《海量运维、运营规划之道》

你应该知道的16个Linux服务器监控命令

《ssh-copy-id帮你建立信任》

《神探tcpdump第五招》-linux命令五分钟系列之三十九

[转]知名互联网公司系统工程师面试题

第四个:fudan_abc的Linux内核专栏

博客介绍:如果你对Linux内核以及usb比较感兴趣,这里将是你的不二选择。本专栏将Linux内核的学习分为四个层次:全面了解,掌握基本功;兴趣导向,选择重点深度钻研。还等什么,让我们一起开始Linux之旅吧!

博客目录摘要(更多精彩内容请进博客):

《Linux那些事儿之我是USB》我是U盘 -- 系列

《Linux内核修炼之道》精华分享与讨论 -- 内核系列

Linux那些事儿 -- 系列

第五个:专栏:Linux 运维

博客介绍:如果你想做运维,Linux运维的话。来这里吧,整个专栏都是关于Linux运维的内容,再不来学习就晚了。教程都在这里你还在犹豫吗?当然此博主还有另一个专栏,写的全是与Linux编程相关的内容,如果你有兴趣同样可以取访问另一个专栏,这里给上这个专栏的链接:专栏:Linux 编程

博客目录摘要(更多精彩内容请进博客):

重装Windows后修复Linux引导

Linux下top命令详解

Shell编程入门(第二版)(下)

Shell编程入门(第二版)(中)

Shell编程入门(第二版)(上)

Linux用户管理案例(第二版)

用户管理实用命令(第二版)

Linux用户管理命令(第二版)

Linux特殊权限分析(第二版)

Linux用户配置文件(第二版)

Vim/Vi实用技巧(第二版)

Vim/Vi常用 *** 作(第二版)

GRUB与Linux系统修复(第二版)

inittab文件剖析[CentOS 5.X](第二版)

CentOS 6.X启动流程

/etc/fstab文件出错,无法进入Linux系统

Linux引导流程(第二版)

Linux备份策略(第二版)

设置磁盘配额(第二版)

/etc/fstab文件分析(第二版)

第五个:最实用的Linux博客

博客介绍:博文收集了很多关于Linux比较实用比较有意义的一些文章和教程。

博客目录摘要(更多精彩内容请进博客)(目录结构分类+文章数量):

linux安全(100)

linux客户端工具(3)

linux开发之汇编(1)

linux性能监控与调整(49)

linux服务器深度历险(电子书)(12)

linux系统管理(336)

linux网站(0)

linux网络管理(138)

第六个:依云's Blog

客介绍:如果大家有仔细翻阅上一篇的python篇的博客,你就会发现这一期将会有一两个博客的重复,因为我实在觉得这两者之间有种强烈的关系。博客大部

分都是关于Linux和Python方面的~看完就是感觉:哇大神。关于Linux方面的内容写的都很有深度。不是很适合新手朋友阅读。

比较适合对系统有所研究的同学。

博客关键词:Linux 、Python

博客目录摘要:

1、发包太快,请勿跟踪

2、Linux 作业控制实践

3、SIGHUP, nohup, disown 以及 expect + sudo + bash + ssh

4、当 SSD 坏掉之后

5、从 slim 到 lightdm

6、交换 ThinkPad 键盘上的 Insert 和 End 键

在上一期的评论区,大家说博客有点多不知道如何下手,今天从以前的10博客缩减到7个博客。如果有选择恐惧症,可以直接选择第一个进行学习。

(待更。。。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/7683891.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-08
下一篇2023-04-08

发表评论

登录后才能评论

评论列表(0条)

    保存