【C】A brief analysis of those things about C

1、sizeof

   sizeof is an operator that calculates the space occupied by "variables" (parameters). Its parameters can be variables, pointers, data types, array names, structures, functions, objects, etc., and its value has been calculated at compile time . Why is sizeof an operator, not a function? Let's take a look at the following code:

int main(void)
{
	int a = 0;

	printf("%d\n", sizeof a);//4
	printf("%d\n", sizeof(a));//4
	printf("%d\n", sizeof int);//error
	printf("%d\n", sizeof(int));//4

	return 0;
}

        Run the above code on a 32-bit machine, and find that the calculation results of sizeof a and sizeof(a) are both 4, and the function is generally represented by fun(...). Come to think of it, is it appropriate to not have parentheses after the function name? Obviously, it is inappropriate. There must be parentheses after the function name, which just shows that sizeof is not a function, but an operator, and the parentheses can be omitted when sizeof calculates the space size of a variable. When sizeof int runs, an error occurs, and the result of sizeof(int) is 4, which shows that sizeof cannot omit parentheses when calculating the size of the data type. (suggestion: don't omit parentheses)

int main(void)
{
	short s = 3;
	int a = 10;

	printf("%d\n", sizeof(s = a + 2));//2
	printf("%d\n", sizeof(s = a));//2
	printf("%d\n", s);//3

	return 0;
}

       Running the above code, it is found that the results of sizeof(s=a+2) and sizeof(s=a) are the same, and the value of s has not changed, which just shows that the expression inside sizeof(...) is not involved in the operation , because memory has been allocated for it during the compilation phase. The following summarizes a few points to note when using sizeof:

a. sizeof (array name), the array name represents the entire array, and it obtains the space size of the entire array;

b. & array name, the array name represents the entire array, and it takes out the address of the entire array;

c. Except for a and b, the array names encountered all refer to the address of the first element of the array (ps: two-dimensional array name a represents one-dimensional array a[0], which is the first address of row 0).

2、strlen

   strlen(...) is a function whose value can only be calculated while the program is running. Its parameter must be of type char * (that is, such as the incoming address), which is used to return the actual length of the string. If some characters are stored in a character array, then the array element should contain '\0', otherwise there will be problems with calculating the value of strlen.

int main(void)
{
	char str [] = {'l', 'o', 'v', 'e'};

	printf("%d\n", strlen(str));//11

	return 0;
}

      Running the above code, the output is:


   Our expected result is to output 4, why does it output 11? This is because when the strlen function calculates the actual length of the string, it will end the calculation when it encounters the first '\0', and the above code is not assigned to the character array '\0', at this time it will keep searching until it finds '\0', so the result is an indeterminate value, which is a rather dangerous operation.

3. Examples

   Next, the difference between sizeof and strlen is consolidated through multiple sets of calculations:

a. One-dimensional array

int a[] = {1,2,3,4};

printf("%d\n",sizeof(a));//16 sizeof(array name) means to calculate the space size of the entire array 4*4=16
printf("%d\n",sizeof(a+0));//4 Represents the address of the 0th element in the array a. There are 32 address buses in 32-bit machines.
                           //So the memory size occupied by the address is 32/8=4
printf("%d\n",sizeof(*a));//4 represents the value of the 0th element in the array a, the elements in the array are integers, and the integers occupy 4 bytes
printf("%d\n",sizeof(a+1));//4 Represents the address of the first element in the array a. There are 32 address buses in 32-bit machines.
                           //So the memory size occupied by the address is 32/8=4
printf("%d\n",sizeof(a[1]));//4 represents the value of the first element in the array a, the elements in the array are integers, and the integers occupy 4 bytes
printf("%d\n",sizeof(&a));//4 &The array name represents the address of the entire array. There are 32 address buses in 32-bit machines.
                          //So the memory size occupied by the address is 32/8=4
printf("%d\n",sizeof(*&a));//16 means to dereference the entire array, that is, the space size of the entire array 4*4=16
printf("%d\n",sizeof(&a+1));//4 means to move the address of the entire array once. There are 32 address buses in 32-bit machines.
                            //So the memory size occupied by the address is 32/8=4
printf("%d\n",sizeof(&a[0]));//4 means to take the address of the 0th element, 32-bit machine has 32 address buses,
                             //So the memory size occupied by the address is 32/8=4
printf("%d\n",sizeof(&a[0]+1));//4 means to take the address of the first element. There are 32 address buses in 32-bit machines.
                               //So the memory size occupied by the address is 32/8=4

b. Character array

char arr[] = {'a','b','c','d','e','f'};

printf("%d\n", sizeof(arr));//6 has no terminator '\0', so the value is 6
printf("%d\n", sizeof(arr+0));//4 Represents the address of the 0th element (that is, 'a'), 32-bit machines have a total of 32 address buses,
                              //So the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(*arr));//1 indicates the address of the first element of the dereferenced array arr, that is, 'a', the element type of the array is char, occupying 1 byte
printf("%d\n", sizeof(arr[1]));//1 means the first element of the array, which is 'b', the element type of the array is char, occupying 1 byte
printf("%d\n", sizeof(&arr));//4 represents the address of the entire array. There are 32 address buses in 32-bit machines, so the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(&arr+1));//4 means to move the address of the entire array once. There are 32 address buses in 32-bit machines.
                               //So the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(&arr[0]+1));//4 means to take the address of the first element (that is, 'b'), a 32-bit machine has a total of 32 address buses,
                                  //So the memory size occupied by the address is 32/8=4

printf("%d\n", strlen(arr));//The random value means starting from the first element, calculating the length of the string, the character array does not have '\0',
                            //At this point it will keep looking until it finds '\0', so the result is an indeterminate value
printf("%d\n", strlen(arr+0));//The random value means starting from the first element, calculating the length of the string, the character array does not have '\0',
                              //At this point it will keep looking until it finds '\0', so the result is an indeterminate value
printf("%d\n", strlen(*arr));//error means to dereference the address of the first element (the 0th element), which is actually the first element 'a',
                             //And the parameter passed to the strlen() function is the address, which is the ASCII value of the passed character 'a', which is obviously illegal
printf("%d\n", strlen(arr[1]));//error means the first element 'b', which is actually passed to the strlen() function
                               //The parameter is the address, which is the ASCII value of the incoming character 'b', which is obviously illegal
printf("%d\n", strlen(&arr));//The random value represents the address of the entire array, the character array does not have '\0', at this time it will always search,
                             //until '\0' is found, so the result is an indeterminate value
printf("%d\n", strlen(&arr+1));//The random value means to move the address of the entire array once, the character array does not have '\0',
//At this time, it will keep looking until it finds '\0', so this result is an indeterminate value, which is 6 different from the random value calculated by strlen(arr)
printf("%d\n", strlen(&arr[0]+1));//The random value indicates that starting from the first element of the array (that is, 'b'), the length of the string is calculated,
//The character array does not have '\0', at this time it will keep looking until '\0' is found, so the result is an indeterminate value,
//Compared with the random value calculated by strlen(arr), the difference is 1
char arr[] = "abcdef";

printf("%d\n", sizeof(arr));//7 string contains '\0', calculate the size of the whole array, so the value is 7
printf("%d\n", sizeof(arr+0));//4 represents the address of the 0th element. There are 32 address buses in 32-bit machines, so the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(*arr));//1 means to dereference the address of the first element (that is, 'a'), the type of element 'a' is char, occupying 1 byte
printf("%d\n", sizeof(arr[1]));//1 means the first element (that is, 'b'), the type of element 'b' is char, occupying 1 byte
printf("%d\n", sizeof(&arr));//4 represents the address of the entire array. There are 32 address buses in 32-bit machines, so the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(&arr+1));//4 means to move the address of the entire array once. There are 32 address buses in 32-bit machines.
                               //So the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(&arr[0]+1));//4 indicates the address of the first element (that is, 'b'). There are 32 address buses in 32-bit machines.
                                  //So the memory size occupied by the address is 32/8=4

printf("%d\n", strlen(arr));//6 arr represents the first address of the array, the string contains the terminator '\0', so the length of the string is 6
printf("%d\n", strlen(arr+0));//6 represents the address of the 0th element, the string contains the terminator '\0', so the length of the string is 6
printf("%d\n", strlen(*arr));//error means to dereference the address of the first element (the 0th element), which is actually the first element 'a',
                             //And the parameter passed to the strlen() function is the address, which is the ASCII value of the passed character 'a', which is obviously illegal
printf("%d\n", strlen(arr[1]));//error means to dereference the address of the first element, which is actually the first element 'b',
                               //And the parameter passed to the strlen() function is the address, which is the ASCII value of the passed character 'b', which is obviously illegal
printf("%d\n", strlen(&arr));//6 represents the address of the entire array, the string contains the terminator '\0', so the length of the string is 6
printf("%d\n", strlen(&arr+1));//The random value means to move the entire array once, but this will skip '\0', then it will keep looking,
                               //until '\0' is found, so the result is an indeterminate value
printf("%d\n", strlen(&arr[0]+1));//5 indicates the address of the first element, that is, the string length is calculated from 'b', so the string length is 5
char *p = "abcdef";

printf("%d\n", sizeof(p));//4 p is a pointer variable, which refers to the address of the first element of the string (that is, 'a'). The 32-bit machine has a total of 32 address buses.
                          //So the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(p+1));//4 The address of the first element of the string pointed to by p+1, a 32-bit machine has a total of 32 address buses,
                            //So the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(*p));//1 means to dereference the first address of p, that is, 'a', char type occupies 1 byte
printf("%d\n", sizeof(p[0]));//1 means the 0th element (that is, 'a'), char type occupies 1 byte
printf("%d\n", sizeof(&p));//4 &p represents the address of the pointer variable, p is a second-level pointer, which can also be understood as the address of the address,
                           //The 32-bit machine has 32 address buses, so the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(&p+1));//4 means to skip a pointer of the size of a pointer variable, a 32-bit machine has a total of 32 address buses,
                             //So the memory size occupied by the address is 32/8=4
printf("%d\n", sizeof(&p[0]+1));//4 Indicates the address of the first element (that is, 'b'). There are 32 address buses in 32-bit machines.
                                //So the memory size occupied by the address is 32/8=4

printf("%d\n", strlen(p));//6 means to calculate the string length from the first address (that is, 'a'), including '\0', so the value is 6
printf("%d\n", strlen(p+1));//5 means to calculate the string length from the address of the first element (that is, 'b'), including '\0', so the value is 5
printf("%d\n", strlen(*p));//error *p refers to 'a', and the address of 'a' passed to the strlen function is the ASCII value of 'a', it's illegal
printf("%d\n", strlen(p[0]));//error p[0] refers to 'a', and the address of 'a' is passed to the strlen function,
                             // is the ASCII value of 'a', which is illegal
printf("%d\n", strlen(&p));//The random value &p represents the address where p is stored, this is an unknown value, I don't know where '\0' is, so this is an uncertain value
printf("%d\n", strlen(&p+1));//The random value means skipping a pointer of the size of a pointer variable, which is not necessarily 4 different from the previous random value,
                             //because '\0' may appear in advance
printf("%d\n", strlen(&p[0]+1));//5 means starting from the address of the first element (that is, 'b'), the length of the calculated string is 5

c. Two-dimensional array

int a[3][4] = {0};

printf("%d\n",sizeof(a));//48 a represents the entire array, the size of the memory space occupied is 4*3*4=48
printf("%d\n",sizeof(a[0][0]));//4 means the element of row 0, column 0, the element type of the array is integer, so it occupies 4 bytes
printf("%d\n",sizeof(a[0]));//16 indicates the name of the array in line 0, which is actually a one-dimensional array with 4 elements, occupying a memory of 4*4=16
printf("%d\n",sizeof(a[0]+1));//4 represents the address of row 0 and column 1. There are 32 address buses in 32-bit machines, so the memory size occupied by the address is 32 /8=4
printf("%d\n",sizeof(a+1));//4 represents the address of the first line, there are 32 address buses in 32-bit machines, so the memory size occupied by the address is 32/8=4
printf("%d\n",sizeof(&a[0]+1));//4 represents the address of the first line, there are 32 address buses in 32-bit machines, so the memory size occupied by the address is 32/8= 4
printf("%d\n",sizeof(*a));//16 indicates the address of the 0th row of the dereferenced array, which is the size of the one-dimensional array a[0], so the memory occupied is 4*4= 16
printf("%d\n",sizeof(a[3]));//16 represents the address of the third line, sizeof() does not participate in the operation, so the value is 4*4=16,
                            //Remember not to think that the array is out of bounds and will not calculate the size of the occupied memory

d. Function

void Func(char str[100]) //void Func(char * str)
{
	return; //sizeof(str) = 4, str is a pointer variable, essentially an address
}

void *p = malloc(100); //sizeof(p) = 4, p is a pointer variable, essentially an address

4、static

   a. Static modifies local variables, which can change the life cycle of the variable, and also modify the storage type of the variable (stack area -> static area), and retain the last calculated value until the end of the program. changes the scope of the variable;

   b. Static modifies global variables or functions, which can only be used in this file, and cannot be used even if declared with extern in other files. The essence is that the external link attribute (global variable has external link attribute) becomes an internal link properties (variables modified by static have internal linkage properties).

   c. Static modified formal parameters, which are stored in the stack area, and the scope is the entire function. The function will only pass the actual parameter to the formal parameter when it is called. If the formal parameter is statically modified, it will be compiled in When allocating memory for it, if the function is never called, then the allocated memory is meaningless, which is actually a waste of memory, so this is not allowed.

   Note: static int a = 0; During the compilation process, through disassembly, it is found that the program will skip this code directly.

5、const

   The const modifier is a constant variable, which has the properties of a constant, and at the same time it can modify the variable.

const int num = 5;
num = 10;//error const modifies the variable num, but num cannot be changed, which means that const has constant attributes
const int n = 5;
int arr[n] = {0};//error Since const has a constant attribute, test whether n can be used as the size of the array,
                 //The result is negative, which means that const modifies variables instead of constants

   const modifies pointer variables ( see who is closest to const )

   When const is placed on the left side of *, the data type on the left side of * (for example, int) can be stroked out with a general stroke to see who is closest to const, leaving only const * p, which means that the content pointed to by p cannot be changed, The pointer variable p can be changed.

int const * p;
const int * p;//The two are equivalent, the content pointed to by the pointer variable p cannot be changed by the pointer, but the pointer variable itself can be changed

   Run the following code and find that *p cannot be changed, while p can be changed.

int main(void)
{
	int num = 10;
	int n = 20;

	const int * p = #//编译报错,左值指定const对象
	p = &n;//const位于*左边时,p可以被改变
	*p = 20;

	return 0;
}

   当const放在*右边时,可以将*左边的数据类型(int)通通用笔划掉,查看const距离谁最近,只留下const p,这就表示p所指向的内容可以被改变,而指针变量p是不能被改变的。

int * const p;//指针变量p不能被改变,但是指针变量指向的内容可以通过指针改变

   运行下面的代码,发现p不可以被改变,而*p可以被改变。

int main(void)
{
	int num = 10;
	int n = 20;

	int * const p = #
	p = &n;//const位于*右边时,p不可以被改变
	*p = 20;

	return 0;
}

   接下来通过一段故事来生动地讲解下const修饰指针变量以及变量的过程中需要注意的事情,需要提前说明的是,被const修饰的指针变量或者变量都不能改变。


const int num = 10;
int n = 20;
const int * p = #
*p = 20;
p = &n;

   num、n均是男生,p是女生,当num把它的地址赋给p时,也就是num与p之间建立了一种关系,称之为“男女朋友关系”。int * const p = &num可以这样理解,男生num说我兜里只有10块钱(const int num=10),不能请你吃饭,女生p心想你都不肯花钱请我吃饭,我得换个男朋友。既然男生num不想花钱请女生吃饭,那么*p(ps:即就是num)不能变为0(当然*p也不能改变为其他值)。const修饰*p,此时p可以改变,于是女生p就说我要和男生n交往,因为男生n有钱(ps:n有20块钱),这时候女生p就与男生n建立了“男女朋友关系”(ps: p = &n),从而断开了与num的联系。

const int num = 10;
int n = 20;
int * const p = #
*p = 20;
p = &n;

   当const放在*右边,p的左边时,这意味着p不能改变,也就是说女生p不能再与男生n建立“男女朋友关系”,这时候*p可以被改变,女生p就对男生num说我可以不换男朋友,但是你得请我吃饭,然后男生num就答应了。

const int num = 10;
int n = 20;
const int * const p = #
*p = 20;
p = &n;

   const int * const p;由于const不仅修饰p,还修饰*p,这就意味着女生p既不能换男朋友num,而她男朋友num又可以不请她吃饭。好惨啊,哈哈……

6、volatile

   编译时不优化,执行时不缓存,并且被volatile修饰的变量只能去内存中读取,而不是在寄存器中读取,它直接存取原始内存地址,保证了内存的可见性。除此之外,volatile还用于多线程和多CPU编程。

const int num = 10;
int * p = (int *)#
*p = 20;//即使num被const修饰,但是仍然可以通过地址去改变num的值,这是不安全的,
//将这段代码保存为test.c文件并在vs中运行,num的值会被改变,若将这段代码保存为test.cpp文件并运行,
//发现num的值不会被改变,而如果在Linux中运行.c文件(gcc test.c -O2),num的值不会被改变,
//这是因为编译器不同而对其作出的不同的处理(或者说是一种优化),num的值如果一直被使用,
//编译器就有可能把num的值存放到寄存器中,便于操作,毕竟寄存器的读取效率更高一些,
//假如这时候编译器已经把num=10保存在了寄存器中,下次访问的时候会直接去寄存器中读取,
//虽然通过指针操作改变了num的值为20,但是由于不会去内存中访问它,就会造成num的值没有改变。
//到底从寄存器去读取这个值还是在内存中去读取,这是一个问题?

volatile const int num = 10; //加上volatile关键字后,编译器在编译时不做出优化,
                             //会保证在内存中读取num的值,而不是在寄存器中,
                             //这样保证了内存的可见性。

a.一个变量可以既是const又是volatile吗?

   可以,比如说,只读的状态寄存器。

b.一个指针可以被volatile修饰吗?

   可以,比如说,当一个中断服务子程序修改一个指向buffer的指针时,就可以是volatile。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325447102&siteId=291194637