C语言
文章平均质量分 91
beyondioi
我,我,我,……我是大舌头。
展开
-
编写高效代码(14) 程序、数据访问符合Cache的时间、空间局部性
Cache正是利用了程序、数据访问时的时间局部性和空间局部性,为了使Cache的访问效率最高,程序和数据的组织,也应该要符合这两个特性。最典型的例子就是二维数组的访问,下面就是一个二维数组:二维数组 如果a[i][j]在Cache中,那么a[i][j+1]就很可能也在Cache中,但是a[i+1][j]则不一定。于是代码这样写就不太好: for(j=0; j转载 2012-12-17 22:56:17 · 883 阅读 · 0 评论 -
编写高效代码(12) 优化内存访问——别让包袱拖垮了你
从理论上看,每条运算指令的执行时间都很短,大多数指令一个Cycle就能完成,很多时候还能一个Cycle执行多条指令,可是实际上,执行指令只是处理器要做的很少一部分工作,处理器还要从存储器中取指令,从存储器中将数据导入到寄存器中,等算完后,再将结果存入到存储器中。 处理器运算的速度像兔子赛跑一样快,但是存储器的访问速度像乌龟走路一样慢,而且越是远离内核的存储器,访问速度越慢。转载 2012-12-17 22:36:12 · 510 阅读 · 0 评论 -
编写高效代码(11) 尽量减少分支
我们在介绍处理器时,已经知道了,现在的处理器都是流水线结构,if和switch等语句会带来跳转,而跳转会打乱流水线的正常执行,影响程序的执行效率。 下面这段代码,把奇数赋一个值,把偶数赋一个值,可以用这种方式实现: [cpp] view plaincopyprint?for(i=0; i { if(i%2 == 0) {转载 2012-12-17 22:29:14 · 565 阅读 · 0 评论 -
编写高效代码(9) 减少处理器不擅长的操作——不要逼我做我不喜欢的事情
尺有所短,寸有所长,每种处理器都有自己擅长与不擅长的操作。 在与处理器配套发布的指令集手册中,都会描述每个指令的执行周期,单周期指令是处理器最喜欢的,不仅执行时间短,而且利于流水线执行。加、减、逻辑运算等,常常是单周期指令,乘、除、分支指令、浮点指令、内存存取操作等,常常需要较多的时钟周期。我们在编程时,就应该少使用执行时间长的指令。 Q:这些复杂指令都有它的用转载 2012-12-17 22:20:18 · 548 阅读 · 0 评论 -
C/C++结构体的一个高级特性――指定成员的位数
在大多数情况下,我们一般这样定义结构体:struct student{ unsigned int sex; unsigned int age;};对于一般的应用,这已经能很充分地实现数据了的“封装”。但是,在实际工程中,往往碰到这样的情况:那就是要用一个基本类型变量中的不同的位表示不同的含义。譬如一个cpu内部的标志寄存器,假设为16 bit转载 2012-12-29 16:01:24 · 471 阅读 · 0 评论 -
一道著名外企面试题的抽丝剥茧
问题:对于一个字节(8bit)的数据,求其中“1”的个数,要求算法的执行效率尽可能地高。分析:作为一道著名外企的面试题,看似简单,实则可以看出一个程序员的基本功底的扎实程度。你或许已经想到很多方法,譬如除、余操作,位操作等,但都不是最快的。本文一步步分析,直到最后给出一个最快的方法,相信你看到本文最后的那个最快的方法时会有惊诧的感觉。解答:首先,很自然的,你想到除法和求余运算,并给出了转载 2012-12-29 15:57:05 · 624 阅读 · 0 评论 -
从两道经典试题谈C/C++中联合体(union)的使用
试题一:编写一段程序判断系统中的CPU是Little endian还是Big endian模式?分析:作为一个计算机相关专业的人,我们应该在计算机组成中都学习过什么叫Little endian和Big endian。Little endian和Big endian是CPU存放数据的两种不同顺序。对于整型、长整型等数据类型,Big endian认为第一个字节是最高位字节(按照从低地址到高地址转载 2012-12-29 15:59:44 · 666 阅读 · 0 评论 -
C语言宏与单井号(#)和双井号(##)
C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念)。下面对常遇到的宏的使用问题做了简单总结。关于#和##在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。比如下面代码中的宏:#define WARN_IF(EXP) /do{ i转载 2012-11-30 11:24:56 · 876 阅读 · 0 评论 -
编写高效代码(7) 减少函数调用——不要老打断我
函数是结构化程序设计的产物,它使代码更加模块化,耦合性更低,重用性更高。不过,函数调用会带来额外的开销,除了引起跳转外,还会产生额外的指令。 人都有这样的经验,做一件事情时,如果被人打断,重新再回来做这件事情,就需要一段恢复时间,如果老是被打断,那事情就没法做了。函数调用也是这样,要进行参数压栈出栈、寄存器保存、指令跳转等。多个步骤如果程序的性能要求较高,就可以将一些小的函数直接转载 2012-12-17 23:02:56 · 675 阅读 · 0 评论 -
编写高效代码(13) 数据对齐访问
在32位处理器中,一个int型变量占4个byte,假设这个变量i在内存中占据2、3、4、5这4个byte的位置,如下图所示。 数据非对齐存储 内核在访问这个数据时,会先将从0开始的4个byte读入到寄存器A中,再将从4开始的4个byte读入到寄存器B中,再将有效的数据拼成一个int数据,放在寄存器C中,可见,这种访问效率是多么的低下啊,如果变量i存储在从0开始的4个byt转载 2012-12-17 22:52:02 · 587 阅读 · 0 评论 -
C/C++宏定义的可变参数
C/C++宏定义的可变参数编写代码的过程中,经常会输出一些调试信息到屏幕上,一般会调用printf这类的函数。但是当调试解决之后,我们需要手工将这些地方删除或者注释掉。最近在看《Linux C编程一站式学习》这本书,就想到一个方法:void myprintf(char* fmt, ...){}#ifdef DEBUG#define printf(fm转载 2012-12-18 13:20:01 · 513 阅读 · 0 评论 -
Volatile深入理解
Volatile深入理解 就象大家更熟悉的const,auto,register等关键字一样,volatile是一个类型修饰符。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。Volatile 是易变的、不稳定的意思。用它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系转载 2013-01-07 19:30:25 · 499 阅读 · 0 评论 -
嵌入式系统开发:C语言中的位结构体
在嵌入式开发中,经常需要表示各种系统状态,位结构体的出现大大方便了我们,尤其是在进行一些硬件层操作和数据通信时。但是在使用位结构体的过程中,是否深入思考一下它的相关属性?是否真正用到它的便利性,来提高系统效率?下面我将进行一些相关实验(这里以项目开发中的实际代码为例):1.位结构体类型设计[cpp] view plaincopyprint?//dat转载 2012-11-26 14:50:57 · 657 阅读 · 0 评论 -
__attribute__((packed))详解
1. __attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法。这个功能是跟操作系统没关系,跟编译器有关,gcc编译器不是紧凑模式的,我在windows下,用vc的编译器也不是紧凑的,用tc的编译器就是紧凑的。例如:在TC下:struct my{ char ch; int a;} sizeof(int)转载 2012-10-31 09:32:57 · 605 阅读 · 0 评论 -
sizeof的用法(附strlen函数)
一、由几个例子说开去。第一个例子: char* ss = "0123456789";sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针sizeof(*ss) 结果 1 ===》*ss是第一个字符char ss[] = "0123456789";sizeof(ss) 结果 11 ===》ss是数组,计算到/0位置,因此是10+1sizeof(*转载 2012-07-25 10:39:13 · 651 阅读 · 0 评论 -
链表之循环链表、双向链表
一、循环链表 循环链表是与单链表一样,是一种链式的存储结构,所不同的是,循环链表的最后一个结点的指针是指向该循环链表的第一个结点或者表头结点,从而构成一个环形的链。 循环链表的运算与单链表的运算基本一致。所不同的有以下几点: 1、在建立一个循环链表时,必须使其最后一个结点的指针指向表头结点,而不是象单链表那样置为NULL。此种情况还使用于在最后一个结点后插入一个新的结点。转载 2011-11-22 15:56:10 · 473 阅读 · 0 评论 -
第7章 内存管理
第7章内存管理 欢迎进入内存这片雷区。伟大的Bill Gates 曾经失言:640K ought to be enough for everybody— Bill Gates 1981程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本章的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管转载 2011-11-22 15:47:23 · 481 阅读 · 0 评论 -
林锐 第6章 函数设计
第6章函数设计函数是C++/C程序的基本功能单元,其重要性不言而喻。函数设计的细微缺点很容易导致该函数被错用,所以光使函数的功能正确是不够的。本章重点论述函数的接口设计和内部实现的一些规则。函数接口的两个要素是参数和返回值。C语言中,函数的参数和返回值的传递方式有两种:值传递(pass by value)和指针传递(pass by pointer)。C++ 语言中多了引用传递(pass转载 2011-11-22 15:50:10 · 1538 阅读 · 0 评论 -
结构体指针说
今天来讨论一下C中的内存管理。记得上周在饭桌上和同事讨论C语言的崛起时,讲到了内存管理方面我说所有指针使用前都必须初始化,结构体中的成员指针也是一样有人反驳说,不是吧,以前做二叉树算法时,他的左右孩子指针使用时难道有初始化吗那时我不知怎么的想不出理由,虽然我还是坚信要初始化的过了几天这位同事说他试了一下,结构体中的成员指针不经过初始化是可以用(左子树和右子树指针)那转载 2011-11-22 15:43:06 · 1411 阅读 · 0 评论 -
C语言中强制数据类型转换
字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128~127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0~255(有些机器把char型当做unsighed char型对待, 取值范围总是0~255)。● 如果一个运算符两边的运算数类型不同,先要将其转换为相同的类型,即较低类型转换为较高类型,然后再参加运算,转换规则如下图所示。转载 2011-11-15 11:35:26 · 36915 阅读 · 1 评论 -
C语言陷阱和缺陷
原著:Andrew Koenig - AT&T Bell Laboratories Murray Hill, New Jersey 07094翻译:lover_P修订:CQBOY来自:http://blog.csdn.net/loverp/archive/2004/08/16/75725.aspx[修订说明] 改正了文中的大部分错别字和格式错误,并对一些句子依照中转载 2011-10-24 16:17:03 · 703 阅读 · 0 评论 -
(*(volatile unsigned long *)0x0012450的理解
对于不同的计算机体系结构,设备可能是端口映射,也可能是内存映射的。如果系统结构支持独立的IO地址空间,并且是端口映射,就必须使用汇编语言完成实际对设备的控制,因为C语言并没有提供真正的“端口”的概念。如果是内存映射,那就方便的多了。 以 #define IOPIN (*((volatile unsigned long *) 0xE0028000)) 为例:作为一个宏定义语句,d转载 2011-10-20 22:00:03 · 1023 阅读 · 1 评论 -
深入理解typedef
typedef作为类型定义关键字,用于在原有数据类型(包括基本类型、构造类型和指针等)的基础上,由用户自定义新的类型名称。 在编程中使用typedef的好处,除了为变量取一个简单易记且意义明确的新名称之外,还可以简化一些比较复杂的类型声明。比如: t转载 2011-10-16 21:57:12 · 425 阅读 · 0 评论 -
C语言宏定义使用技巧
C语言宏定义使用技巧 写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等。下面列举一些成熟软件中常用得宏定义…… 1,防止一个头文件被重复包含 #ifndef COMDEF_H #define COMDEF_H //头文件内容 #endif 2,重新定义一些类型,防止由于各种平台和编译器的不同,而产生的转载 2011-11-22 15:58:07 · 471 阅读 · 0 评论 -
经典c 教程(ch7 指针和内存分配---下)
7.15 数组的大小可以在程序运行时定义吗? 不。在数组的定义中,数组的大小必须是编译时可知的,不能是在程序运行时才可知的。例如,假设i是一个变量,你就不能用i去定义一个数组的大小: char array[i]; /*(notvalidc */ 有些语言支持这种定义,但C语言不支持。如果C语言支持这种定义,栈就会变得更复杂,调用函数的开销就会更大,而程转载 2011-11-22 16:03:08 · 823 阅读 · 0 评论 -
彻底了解指针数组,数组指针,以及函数指针,以及堆中的分配规则
指针数组和数组指针下面就简单说说这两个概念:一:指针数组,顾名思义,就是说的首先是一个数组吧,然后数组的元素是指针而已。说明形式为:type *pointer_array[constant1][constant2]...[constantn];例如:int *pai[3];由于‘*’是自右向左结合,因此从右向左看,首先看到[4]说明是一个数组,是一个包含4个元素的数组,然后转载 2011-11-22 16:09:16 · 2049 阅读 · 0 评论 -
堆和栈的区别
一、预备知识—程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其 操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回 收 。注意它与数据结构中的堆是两转载 2012-07-25 10:37:25 · 407 阅读 · 0 评论 -
数组名和指针的区别
魔幻数组名 请看程序(本文程序在WIN32平台下编译):1. #include 2. int main(int argc, char* argv[])3. {4. char str[10];5. char *pStr = str;6. cout 7. cout 8. return 0;9. } 1、数组名不是指针 我们先来转载 2012-07-07 09:40:19 · 1161 阅读 · 1 评论 -
C语言的内存分配
文章一、C语言的内存分配模型1、程序代码区:存放函数体的二进制代码。 2、全局区数据区:全局数据区划分为三个区域。全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。常量数据存放在另一个区域里。这些数据在程序结束后由系统释放。我们所说的BSS段(bss segment)通常是指用来存放程序中未初始化的全转载 2012-07-07 11:12:40 · 521 阅读 · 0 评论 -
小议大小端模式对C语言的共用体结构的影响
小议大小端模式对C语言的共用体结构的影响1、一些问题问题1view plaincopy to clipboardprint?#include "stdio.h" union { int i; char ch[2]; }key; main() { key.i=65*256+66; printf("%c\t%c转载 2011-12-29 21:00:36 · 628 阅读 · 0 评论 -
嵌入式软件工程师面试题
嵌入式软件工程师面试题预处理器(Preprocessor)1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在这想看到几件事情: 1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等) 2). 懂得预处理器将为你计算转载 2011-11-15 10:56:28 · 733 阅读 · 0 评论 -
第5章 常量--变量C++/C 编程指南,v 1.0
第5章常量 常量是一种标识符,它的值在运行期间恒定不变。C语言用 #define来定义常量(称为宏常量)。C++ 语言除了 #define外还可以用const来定义常量(称为const常量)。5.1为什么需要常量如果不使用常量,直接在程序中填写数字或字符串,将会有什么麻烦?(1) 程序的可读性(可理解性)变差。程序员自己会忘记那些数字或字符串是什么意思,用户则更加转载 2011-11-22 15:53:47 · 488 阅读 · 0 评论 -
c/c++标准预定义宏
一、标准预定义宏The standard predefined macros are specified by the relevant language standards, so they are available with all compilers that implement those standards. Older compilers may not provide all转载 2011-11-22 16:06:35 · 596 阅读 · 0 评论 -
C/C++内存管理详解
程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。1、内存分配方式内存分配方式有三种:(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。(2)转载 2011-11-22 16:12:03 · 527 阅读 · 0 评论 -
深入理解指针函数
1.指针函数的定义 顾名思义,指针函数即返回指针的函数。其一般定义形式如下: 类型名 *函数名(函数参数表列); 其中,后缀运算符括号“()”表示这是一个函数,其前缀运算符星号“*”表示此函数为指针型函数,其函数值为指针,即它带回来的值的类型为转载 2011-10-16 21:59:48 · 397 阅读 · 0 评论