下面是我认为较为完整好理解的说法
在我们开始之前,我想指出,本文中给出的定义和建议是指目前最流行的体系结构(IA-32、Intel 、IA-),可能并不完全适用于一些特殊的体系结构。
For (int I = 0;I < n;I ++) a[I] = 0;
随着微处理器的发展和容量的增加,进一步增加int类型的大小就变得不合理了。这有很多原因:使用的内存的经济性,最大的可移植性等。因此,出现了几个声明C/ c++基类型关系的数据模型。表N1显示了主要的数据模型,并列出了使用它们的最流行的系统。
总结,就是说,由于不同版本的电脑系统,int,short,long这些玩意在不同位数的电脑中内存空间不同,比如说,你在Microsoft Win(X}IA),就是表中第6行里面的计算机用int(这里是4字节存了一个很大的数据,这样如果在PDP-11 Unix (1973),就是表中第1行里面的计算机,用这个计算机打开的话,这样那个数据有可能就是有问题的,因为在PDP-11 Unix (1973)中,int是一个2字节的数据类型
For (ptrdiff_t I = 0;I < n;I ++) a[I] = 0;
正是这些代码提供了安全性、可移植性和良好的性能。本文的其余部分将解释其中的原因。
size_t类型是C和c++语言的基本无符号整数类型。//就是说他是正整数,和那个unsigned很像
它是sizeof操作符返回的结果的类型。
sizeof操作符的作用是返回一个对象或类型名的长度,返回值的类型为size_t,长度的单位是字节。sizeof表达式的结果是编译时常量,该操作符有一下三种语法形式:
sizeof(type name); sizeof(expr); sizeof expr;
选择类型的大小,以便它可以存储理论上可能的任何类型的数组的最大大小。
在32位系统上size_t为32位,而在位系统上size_t为位。
换句话说,size_t类型的变量可以安全地存储指针。
例外是指向类函数的指针,但这是一个特殊情况。
size_t类型的最大可能值是常量SIZE_MAX。
ptrdiff_t类型是C和c++语言的带符号整数类型。
选择类型的大小,以便它可以存储理论上可能的任何类型的数组的最大大小。
在32位系统上,ptrdiff_t是32位,在位系统上是位。
与size_t一样,ptrdiff_t可以安全地存储指针,但指向类函数的指针除外。
另外,ptrdiff_t是一个表达式的结果类型,其中一个指针减去另一个指针(ptr1-ptr2)。
Ptrdiff_t类型有其同义词intptr_t,其名称更清楚地表明它可以存储指针。
size_t和ptrdiff_t类型使您能够编写可移植性良好的代码。使用size_t和ptrdiff_t类型创建的代码很容易移植。size_t和ptrdiff_t的大小总是与指针的大小一致。正因为如此,这些类型应该被用作大型数组的索引,用于存储指针和指针算术。
linux应用程序开发人员通常使用长类型来实现这些目的。在Linux中接受的32位和位数据模型框架中,这确实是可行的。Long类型的大小与指针的大小一致。但是这段代码与Windows数据模型不兼容,因此您不能认为它易于移植。更正确的解决方案是使用类型size_t和ptrdiff_t。
作为size_t和ptrdiff_t的替代,windows开发人员可以使用类型DWORD_PTR, size_t, SSIZE_T等。但是,为size_t和ptrdiff_t类型仍然是可取的。
这里有一个简单的例子:
Size_t n =…For (unsigned I = 0;I < n;I ++) a[I] = 0;
如果我们处理的数组包含超过UINT_MAX项,这段代码是不正确的。检测错误并预测这段代码的行为并不容易。调试版本将挂起,但几乎没有人会在调试版本中处理千兆字节的数据。而发布版本(取决于优化设置和代码的特性)可以挂起,也可以突然正确地填充所有数组单元格,从而产生正确操作的错觉。因此,在程序中出现浮动错误,随着代码的细微更改而发生和消失。要了解更多关于这种虚幻错误及其危险后果的信息,请参阅文章“一匹位的马,可以计数”[1]。
另一个“休眠”错误的例子,发生在输入数据的特定组合(a和B变量的值):
int A = -2;
unsigned B = 1;
Int数组[5]= {1,2,3,4,5};
Int *ptr = array + 3;
ptr = ptr + (A + B);
//错误printf("%i\n", *ptr);
这段代码将在32位版本中正确执行,并打印数字“3”。在位模式下编译后,执行代码时会出现失败。让我们检查一下代码执行的顺序和错误的原因:
这种错误可以通过使用size_t或ptrdiff_t类型轻松避免。在第一种情况下,如果“i”变量的类型是size_t,就不会有无限循环。在第二种情况下,如果我们对“A”和“B”变量使用size_t或ptrdiff_t类型,我们将正确地打印数字“3”。
让我们制定一个指导方针:无论在哪里处理指针或数组,都应该使用size_t和ptrdiff_t类型。
要了解有关使用size_t和ptrdiff_t类型可以避免的错误的更多信息,请参阅以下文章:
举例说明size_t类型相对于unsigned类型的优势是很困难的。为了客观,我们应该使用编译器的优化功能。而优化代码的两种变体经常因为太过不同而无法显示这种差异。我们在第六次尝试时才创建了一个简单的例子。这个例子仍然不理想,因为它演示的不是我们上面提到的那些不必要的数据类型转换,而是当使用size_t类型时,编译器可以构建更有效的代码。让我们考虑一个程序代码,以反序排列数组的项:
无符号arraySize;
For (unsigned I = 0;i < arraySize / 2;i++)
{浮点值=数组[I];
array[i] = array[arraySize - i - 1];
数组[arraySize - i - 1] = value;}
在本例中,"arraySize"和"i"变量具有unsigned类型。这种类型可以很容易地用size_t类型替换,现在比较图1所示的一小段汇编程序代码。
图N1。使用unsigned类型和size_t类型时位汇编程序代码的比较
当使用位寄存器时,编译器设法构建更简洁的代码。我不确定使用unsigned类型创建的代码会比使用size_t创建的代码运行得慢。比较现代处理器上的代码执行速度是一项非常困难的任务。但是从示例中可以看到,当编译器使用位类型操作数组时,它可以构建更短、更快的代码。
根据我自己的经验,我可以说,用ptrdiff_t和size_t合理地替换int和unsigned类型,可以在位系统上为您提供高达10%的额外性能增益。在“在Visual c++中开发资源密集型应用程序”[5]文章的第四节中,您可以看到使用ptrdiff_t和size_t类型时提高速度的示例。
正如读者所看到的,使用ptrdiff_t和size_t类型为位程序提供了一些优势。但是,它并不是用size_t类型替换所有无符号类型的全面解决方案。首先,它不能保证程序在位系统上的正确操作。其次,由于这种替换,很可能会出现新的错误,违反数据格式兼容性等等。您不应该忘记,在此替换之后,程序所需的内存大小也将大大增加。增加必要的内存大小将减慢应用程序的工作,因为缓存将存储更少的对象。
因此,在旧代码中引入ptrdiff_t和size_t类型是一项需要大量时间的逐步重构任务。实际上,您应该通读整个代码并进行必要的修改。实际上,这种方法既昂贵又低效。有两种可能的变体:
在标准C库中的许多函数使用的参数或者返回值都是表示的用字节表示的对象大小,比如说malloc(n) 函数的参数n指明了需要申请的空间大小,还有memcpy(s1, s2, n)的最后一个参数,表明需要复制的内存大小,strlen(s)函数的返回值表明了以’\0’结尾的字符串的长度(不包括’\0’),其返回值并不是该字符串的实际长度,因为要去掉’\0’。
或许你会认为这些参数或者返回值应该被申明为int类型(或者long或者unsigned),但是事实上并不是。C标准中将他们定义为size_t
。标准中记载malloc的申明应该出现在,定义为:
void *malloc(size_t n);
memcpy和strlen的申明应该出现在中:
void *memcpy(void *s1, void const *s2, size_t n);
size_t strlen(char const *s);
size_t还经常出现在C++标准库中,此外,C++库中经常会使用一个相似的类型size_type,用的可能比size_t还要多。
size_t类型是一个类型定义,通常将一些无符号的整形定义为size_t,比如说unsigned int或者unsigned long,甚至unsigned long long。每一个标准C实现应该选择足够大的无符号整形来代表该平台上最大可能出现的对象大小。
size_t和unsigned int有所不同,size_t的取值range是目标平台下最大可能的数组尺寸
一些平台下size_t的范围小于int的正数范围,又或者大于unsigned int.
最典型的,在x下,int还是4,但size_t是8.
这意味着你在x下最大可能开辟的数组尺寸是2^.
如果你使用int或者unsigned int,那么在x下如果你的代码中全部使用uint作为数组的尺寸标记,
那么你就会失去控制2^32尺寸以上的数组的机会.
目前的int普遍是32位,而size_t在主流平台中都是位。
size_t为什么存在?因为无论int还是unsigned都很可能小于size_t需要的大小,所以必须有个size_t。
对_t有疑惑。
这个问题很简单,仅仅是因为作者选择这样的命名作为编码规范而已。类型名与变量名共享相同的命名空间,所以通常需要在命名方面刻意区分出来。
在遥远的 C 时代,发明者很可能是想建议所有的类型名后面加_t,只不过这并没有成为更普遍的编码规范罢了。而现今Java的规范倒比较容易让人接受:大写开头的是类型名,小写开头的是变量名跟函数名,虽然具体细则有不同,但原意都是一样的:变量与类型共享同一个命名空间,因而需要在命名规则上刻意区分开来。
_t的意思显然就是type,这没啥好解释的。关于为什么要加_t。
一个类型后面加了_t说明了这是一个POSIX或GNU保留类型,防止namespace pollution的。
不然标准库里新加了什么类型说不定就和用户已经定义的类型重名了。
所以POSIX规定自己扩展的类型都加_t,这样只要用户定义类型的时候不加_t就不会冲突。
因为unsigned int
不是唯一的无符号整数类型。size_t
可以是任意的unsigned char
,unsigned short
,unsigned int
,unsigned long
或unsigned long long
,取决于实施。
引用:https://www.zhihu.com/question/24773728/answer/210728099
https://www.zhihu.com/question/24773728/answer/210659978
https://www.zhihu.com/question/24773728/answer/220149
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- bangwoyixia.com 版权所有 湘ICP备2023022004号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务