C语言填坑之sizeof与strlen的比较
一、sizeof
1、本质
单目运算符,目的是获取变量或类型占用的存储空间(单位:字节)。
2、原型
入参:类型、变量名;
出参:size_t,即unsigned int
3、原理:指针偏移
非数组:#define _sizeof(T) ((size_t)((T*)0 + 1))
数组:#define array_sizeof(T) ( (size_t)(&T+1) - (size_t)(&T) )
4、作用阶段:
编译时(内部的赋值等语句的副作用不会发生,如sizeof(i++))
5、注意事项:
(1)不能计算动态分配空间的大小;
(2)作用于数组,编译时分配的数组空间大小;作用于类型,该类型所占空间大小;作用于指针,存储该指针所用空间的大小;作用于函数,决定于函数的返回值类型大小;(仅需要区分数组与类型,指针与函数是类型的特例)
(3)sizeof 作用于结构体,基本类型相加,注意字节对齐;
(4)各类型占用的空间大小与操作系统有关;
(5)C99特性,变长数组在运行时计算数组长度
二、strlen
1、本质:标准库函数,目的是获取字符串的字符个数(不包括结束符,单位:个)。
2、原型:
头文件:string.h
原型:size_t strlen(char const* str);
3、原理:
遍历计数,以结束符为截止条件:
size_t strlen(char const* str)
{
size_t ret = 0;
while(*str++) {
ret++;
}
return ret;
}
4、作用阶段:运行时
5、注意事项:
(1)函数仅统计从字符串起始位置到’\0’为止的字符个数,正确计算时要求字符串有结束符,并且如果字符串中有多个结束符,仅计算到第一个结束符。
(2)仅计算字符个数,与操作系统无关;
三、sizeof数组长度计算说明
(1)计算公式:#define array_sizeof(T) ((size_t)(&T+1) - (size_t)(&T))
假设数组a[100],a和 &a结果都是数组的首地址,但其类型不一样:
a表示&a[0],即对数组首元素取地址,a+1表示首地址+sizeof(元素类型);
&a尽管值为数组首元素地址,但类型为:类型 (*)[数组元素个数],&a+1大小为:首地址+sizeof(a)。
因此,&T+1指针将会指到数组的末尾,尾地址减去首地址,得出的正是数组的大小。
验证实例:
#include<stdio.h>
#include<string.h>
#define sizeof_type(T) ((size_t)((T*)0 + 1))
int main()
{
char str[]="hello";
char *p = str;
printf("str_p=%p, &str_p=%p\n", str, &str);
printf("str_p+1=%p, &str_p+1=%p\n", str + 1, &str + 1);
printf("str_mem=%d, p_mem=%d\n", sizeof(str), sizeof(p));
printf("str_len=%d, p_len=%d\n", strlen(str), strlen(p));
printf("sizeof_int=%d, my_sizeof_len=%d\n", sizeof(int), sizeof_type(int));
printf("sizeof_type=%d\n", ((size_t)((int*)0 + 1)));
printf("sizeof_p=%p\n", (double*)0);
printf("sizeof_p=%p\n", (double*)0 + 1);
return 0;
}