C/C++中的重点问题
以《C和指针》、《C专家编程》、《C陷阱与缺陷》中描述的问题点为主要方向,解惑...
存墨
做一个有情怀的程序员
展开
-
多线程实现生产者-消费者问题——C++版本
问题描述:1)生产者进程每次生产1个产品(产品数量大于4时停止生产);2)消费者进程每次消耗2个产品;#include <iostream>#include <thread>#include <mutex>#include <condition_variable>using namespace std;std::mutex mu;std::condition_variable cond;void ProduceThread(int *pr原创 2022-04-03 13:36:02 · 1537 阅读 · 0 评论 -
如何获取代码片段执行的时间
问题:在实际工作中,需要计算某一个程序中代码片段的执行时间,从而判断这部分代码放在驱动层处理更高效还是放在用户层处理更合适。这里用到的结构体是timeval,通过函数gettimeofday()来获取代码片段起始时间值,从而计算片段执行时间;代码如下:#include <stdio.h>#include <unistd.h>#include <sys/time.h>#define START_TIME \ struct timeval time1, ti原创 2021-12-08 21:49:26 · 1106 阅读 · 0 评论 -
库函数调用和系统调用的区别
在日常工作中一般会根据不同的情况选择使用系统调用或者库函数,对于它们有什么区别列在下面:原创 2021-12-07 22:34:33 · 95 阅读 · 0 评论 -
函数中的变量为什么要放在“栈”中?
当我们要解释这个问题时,我们首先回顾一下函数的调用是如何实现的;有如下的代码:int Add(int &a, int &b){ int p = 2 * a; int q = 4 * b; return p + q;}int main(){ int m = 10; int n = 20; int x = Add(m, n); int y = 3*x; return 0;}上图对应上面的代码:当程序执行到point a时,系统先保存当前的上下文——也就是把原创 2021-11-29 21:40:08 · 443 阅读 · 0 评论 -
为什么C语言(包括大多数高级语言)中的数组下标从0开始
在C语言中,所有定义的变量最终都是加载到内存中进行相关的操作的,包括数组;数组在内存中占据的空间是连续的,而且数组的每个元素都是相同的数据类型。这就决定了我们在访问数组时必须能够找到这一连续内存空间的首地址,而这个首地址自然就落到了数组名的肩上。此时,**这个首地址就是第一个元素的地址;这样一来,当需要访问其他数据元素时都需要和这个首地址进行关联,数组的下标实际上表示的意义是:数组中元素位置与首地址的偏移量。**因此在C语言中数组的第一个元素下标即为0。另一种理解方式可以和自然数做类比:最小的自然数是0而原创 2021-11-26 20:08:30 · 2024 阅读 · 0 评论 -
C语言中什么情况下“指针”等价于“数组名”
第一种情况:表达式中引用的数组名就是“指针”;char str[10] = "abcdefg";printf("%c\n", *(str + 4));第二种情况:数组的下标引用和指针偏移量的使用等价;char str[10] = "abcdefg";char *p = str;printf("%s\n", p);第三种情况:数组作为函数的形参时“退化”为指针;#include <stdio.h>void TestFunc(char str[]){ printf("si原创 2021-11-22 21:38:57 · 1287 阅读 · 1 评论 -
C语言中static的作用
1.隐藏与隔离的作用:将一个全局变量声明为staic 类型,那么该变量就只能在本文件内被引用,从而起到了隔离的作用,这样做有利于模块化设计;2.保持内容的稳定性(不被意外释放)对于一个函数内部的普通变量,当函数执行完之后该变量的生存期随之结束,紧接着就被释放;如果加上了static关键字,该变量就具有了模块属性;该变量只能在本模块使用,而不能被其他模块引用;3.限定函数的使用范围被static 修饰的函数只能被本模块内的函数调用,而不能被模块外函数调用。...原创 2021-11-16 23:32:18 · 706 阅读 · 0 评论 -
main函数执行之前会做什么?
根据以下代码写出运行结果:#include <iostream>using namespace std;class App{public: App(){ cout << "constructor of App" << endl;} ~App(){ cout << "destructor of App" << endl;}};App app1;int main(){ cout << "main start." &原创 2021-11-15 23:00:54 · 1025 阅读 · 0 评论 -
关于C语言中的#和##问题
C语言中对#和##的处理都是在编译阶段执行,往往是以宏定义的方式处理;C语言中#exp是将exp进行字符串化——也就是将#后处理成字符串;C语言中##是标识符连接符号,r##Log代表的是标识符rLog(当然rLog必须已经定义);以下是示例代码:#include <stdio.h>#define STRIZE(exp) #exp#define STRLINK(symbol) int_##symbolint main(){ int a = 100; int b = 200.原创 2021-11-13 16:27:27 · 679 阅读 · 0 评论 -
计算机中的大小端问题
所谓的大小端问题指的是计算机加载数据是内存实际存储顺序和数据本身的“高/低位”顺序是否一致的问题;当数据长度大于1时才有大小端的讨论意义;在C语言(32位机)中short占2个字节,那么当我们定义一个short型(0x1234)的变量时就会向图1中的字节1和字节2写入两个字节;这时就有两种可能的情况:1)字节1存储“0x12”,字节2存储“0x34”;【大端模式】2)字节1存储“0x34”,字节2存储“0x12”;【小端模式】如下图:那么如何判断呢?这里我们很自然地就想到如果我们读到低地址的数原创 2021-10-30 23:20:34 · 521 阅读 · 0 评论 -
数组与指针引起的语义“陷阱”
32位系统中1.指针++和变量++的区别在C语言中基本数据类型在内存中所占空间是不同的,比如char型1个字节,short型2个字节,int型4个字节,float型4个字节…然而指针类型所占字节只和处理器的位数有关,比如32位系统的指针变量一般为4个字节;int a[] = {1,2,3,4,5,6,7};int x = a[0];int *p = a;printf("++x=%d\n", ++x);printf("%p\n", p);printf("%p\n", a);printf("原创 2021-10-16 23:25:36 · 109 阅读 · 0 评论 -
词法分析中的“贪心原则”
C语言中的某些符号只有一个字符长度,我们把这样的符号成为“单字符符号”;相应的,有的符号包含了多个字符,称为“多字符符号”;举例:单字符符号:+、、/、=;多字符符号:+=、->、++、–、/;C编译器在读入一个字符’/'之后又跟了一个‘*’,那么这时候该如何处理呢?比如下面的代码:int a = 10, b, c=100;int *p = &a;b = c/*p;C编译器的处理方法如下:每一个符号应该包含尽可能多的字符。也就是说,从左到右一个一个地读入字符,如果该字符可能组原创 2021-10-16 20:33:07 · 208 阅读 · 0 评论 -
C程序的编译过程和代码在内存中的分布情况(gcc为例)
1.一个完整且没有语法错误的C文件编译过程如下:第一步:预处理(preprocessing)【有的地方也叫预编译】,这一步主要就是要将.h文件中的内容插入.c文件中(一般含有main函数)、将宏定义进行展开,生成.i文件以备后续进行处理;第二步:编译(compilation)将第一步中生成的.i文件生成汇编代码,输出为.s文件;第三步:汇编(assembly)将第二步生成的.s文件生成.o文件;第四步:链接(linking)将第三步生成的.o文件生成最终的可执行代码(一般情况下如果不指定文件名将会生原创 2021-10-15 00:22:40 · 346 阅读 · 0 评论