一篇讲对齐比较好的文章,转贴如下:
大致标注一二:
1.内存对齐:计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数k则被称为该数据类型的对齐模数(alignment modulus)
2.不同编译器默认的最大对齐字节数是不一样的,比如vc==8,gcc==4,可以通过#progma pack (n)来修改,分析程序的时候要注意编译器的区别
3.一个结构体里面,按照alignment modulus最大的数据成员来进行对齐,超过编译器规定最大的对齐字节个数,按编译器最大对齐字节个来
4.double类型在vc里面alignment modulus == 8,而在gcc里面由于默认最大对齐个数是4,不设置的话,alignment modulus == 4
5.因为数组各元素之间不能有空隙,所以{int a;char b;}
这种情况,默认在VC里面也需要占8个字节.
正文如下:
当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将如何在内存中放置这些字段?ANSI C对结构体的内存布局有什么要求?而我们的程序又能否依赖这种布局?这些问题或许对不少朋友来说还有点模糊,那么本文就试着探究它们背后的秘密。
首先,至少有一 ......
一篇讲对齐比较好的文章,转贴如下:
大致标注一二:
1.内存对齐:计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数k则被称为该数据类型的对齐模数(alignment modulus)
2.不同编译器默认的最大对齐字节数是不一样的,比如vc==8,gcc==4,可以通过#progma pack (n)来修改,分析程序的时候要注意编译器的区别
3.一个结构体里面,按照alignment modulus最大的数据成员来进行对齐,超过编译器规定最大的对齐字节个数,按编译器最大对齐字节个来
4.double类型在vc里面alignment modulus == 8,而在gcc里面由于默认最大对齐个数是4,不设置的话,alignment modulus == 4
5.因为数组各元素之间不能有空隙,所以{int a;char b;}
这种情况,默认在VC里面也需要占8个字节.
正文如下:
当在C中定义了一个结构类型时,它的大小是否等于各字段(field)大小之和?编译器将如何在内存中放置这些字段?ANSI C对结构体的内存布局有什么要求?而我们的程序又能否依赖这种布局?这些问题或许对不少朋友来说还有点模糊,那么本文就试着探究它们背后的秘密。
首先,至少有一 ......
首先看下下面这段:
int main()
{
char *name = "fengkewei";
char name1[] = "fengkewei";
char *name2 = "fengkewei";
char *name3 = "woaifengkewei";
int i = 10;
int j = 10;
int k = 11;
return 0;
}
若您觉得它们应该都保存在内存中的一块地方,那请往下看。。。。
下面是编译器为各个变量分配的内存地址,由于分配在栈上 所以地址是递减的
---------------------栈区------------------------------------
+ &name 0x0013ff5c unsigned char * *
+ &name1 0x0013ff48 unsigned char [10]*
+ &name2 0x0013ff3c unsigned char * *
+ &name3 0x0013ff30 unsigned char * *
+ &i 0x0013ff24 int *
+ &j 0x0013ff18 int *
+ &k 0x0013ff0c int *
---------------------------------------------------------------
&name 和&name1[] 相差20个字节 但"fengkewei"只有10个字节(带空字符)
&name1[]和&name2 相差12个字节
后面都正常了 都差12
为什么是12?
——————&mda ......
首先看下下面这段:
int main()
{
char *name = "fengkewei";
char name1[] = "fengkewei";
char *name2 = "fengkewei";
char *name3 = "woaifengkewei";
int i = 10;
int j = 10;
int k = 11;
return 0;
}
若您觉得它们应该都保存在内存中的一块地方,那请往下看。。。。
下面是编译器为各个变量分配的内存地址,由于分配在栈上 所以地址是递减的
---------------------栈区------------------------------------
+ &name 0x0013ff5c unsigned char * *
+ &name1 0x0013ff48 unsigned char [10]*
+ &name2 0x0013ff3c unsigned char * *
+ &name3 0x0013ff30 unsigned char * *
+ &i 0x0013ff24 int *
+ &j 0x0013ff18 int *
+ &k 0x0013ff0c int *
---------------------------------------------------------------
&name 和&name1[] 相差20个字节 但"fengkewei"只有10个字节(带空字符)
&name1[]和&name2 相差12个字节
后面都正常了 都差12
为什么是12?
——————&mda ......
和在IDE中编译相比,命令行模式编译速度更快,并可以避免被IDE产生的一些附加信息所干扰。本文将介绍微软C/C++编译器命令行模式设定和用法。 1、设置环境变量: PATH=C:\Program Files\Microsoft Visual Studio 8\VC\bin INCLUDE=C:\Program Files\Microsoft Visual Studio 8\VC\include LIB=C:\Program Files\Microsoft Visual Studio 8\VC\lib 如果提示找不到mspdb80.dll文件,则从C:\Program Files\Microsoft Visual Studio 8\Common7\IDE下拷贝“msobj80.dll,mspdb80.dll,mspdbcore.dll,mspdbsrv.exe”这四个文件到C:\Program Files\Microsoft Visual Studio 8\VC\bin下即可。 2、命令选项: 1) /C:在预处理输出中保留注释语句 2) /c:只编译,不连接,相当于在"Build"菜单下选择了"Compile" 3) /D:定义常量和宏,与源程序里的#define 有相同效果 4) /E:预处理C、C++源文件,将源文件中所有的预编译指令及宏展开,将注释去掉,然后将预处理器的输出拷贝至标准输出设备输出,并且在每个文件的开头和末尾加� ......
和在IDE中编译相比,命令行模式编译速度更快,并可以避免被IDE产生的一些附加信息所干扰。本文将介绍微软C/C++编译器命令行模式设定和用法。 1、设置环境变量: PATH=C:\Program Files\Microsoft Visual Studio 8\VC\bin INCLUDE=C:\Program Files\Microsoft Visual Studio 8\VC\include LIB=C:\Program Files\Microsoft Visual Studio 8\VC\lib 如果提示找不到mspdb80.dll文件,则从C:\Program Files\Microsoft Visual Studio 8\Common7\IDE下拷贝“msobj80.dll,mspdb80.dll,mspdbcore.dll,mspdbsrv.exe”这四个文件到C:\Program Files\Microsoft Visual Studio 8\VC\bin下即可。 2、命令选项: 1) /C:在预处理输出中保留注释语句 2) /c:只编译,不连接,相当于在"Build"菜单下选择了"Compile" 3) /D:定义常量和宏,与源程序里的#define 有相同效果 4) /E:预处理C、C++源文件,将源文件中所有的预编译指令及宏展开,将注释去掉,然后将预处理器的输出拷贝至标准输出设备输出,并且在每个文件的开头和末尾加� ......
用此法前确保你的C源代码是无错的~~
解决办法:
C:
在主函数后加getch()或ch=getch(); (让程序等待你按下任意键,再继续执行下面的语句)
C++:
1.包含头文件时: #include <stdlib.h>/*header file,因为在stdlib.h头文件中定义了system()函数*/
2.在最后一句加上:system("PAUSE");//system函数,Pause属于DOS命令
实际上system函数是可以调用一些DOS命令
以下为DOS命令:
ASSOC 显示或修改文件扩展名关联。
AT 计划在计算机上运行的命令和程序。
ATTRIB 显示或更改文件属性。
BREAK 设置或清除扩展式 CTRL+C 检查。
CACLS 显示或修改文件的访问控制列表(ACLs)。
CALL 从另一个批处理程序调用这一个。
CD 显示当前目录的名称或将其更改。
CHCP 显示或设置活动代码页数。
CHDIR 显示当前目录的名称或将其更改。
CHKDSK 检查磁盘并显示状态报告。
CHKNTFS 显示或修改启动时间磁盘检查。
CLS 清除屏幕。
CMD 打开另一个 Windows 命令解释程序窗口。
COLOR 设置默认控制台前景和背景颜色。
COMP 比较两个或两套文件的内容。
COMPACT 显示或更改 NTFS 分区上文件的压缩。
CONVERT 将 FAT 卷转换成 N ......
用此法前确保你的C源代码是无错的~~
解决办法:
C:
在主函数后加getch()或ch=getch(); (让程序等待你按下任意键,再继续执行下面的语句)
C++:
1.包含头文件时: #include <stdlib.h>/*header file,因为在stdlib.h头文件中定义了system()函数*/
2.在最后一句加上:system("PAUSE");//system函数,Pause属于DOS命令
实际上system函数是可以调用一些DOS命令
以下为DOS命令:
ASSOC 显示或修改文件扩展名关联。
AT 计划在计算机上运行的命令和程序。
ATTRIB 显示或更改文件属性。
BREAK 设置或清除扩展式 CTRL+C 检查。
CACLS 显示或修改文件的访问控制列表(ACLs)。
CALL 从另一个批处理程序调用这一个。
CD 显示当前目录的名称或将其更改。
CHCP 显示或设置活动代码页数。
CHDIR 显示当前目录的名称或将其更改。
CHKDSK 检查磁盘并显示状态报告。
CHKNTFS 显示或修改启动时间磁盘检查。
CLS 清除屏幕。
CMD 打开另一个 Windows 命令解释程序窗口。
COLOR 设置默认控制台前景和背景颜色。
COMP 比较两个或两套文件的内容。
COMPACT 显示或更改 NTFS 分区上文件的压缩。
CONVERT 将 FAT 卷转换成 N ......
BoundsChecker采用一种被称为 Code Injection的技术,来截获对分配内存和释放内存的函数的调用。简单地说,当你的程序开始运行时,BoundsChecker的DLL被自动载入进程的地址空间(这可以通过system-level的Hook实现),然后它会修改进程中对内存分配和释放的函数调用,让这些调用首先转入它的代码,然后再执行原来的代码。BoundsChecker在做这些动作的时,无须修改被调试程序的源代码或工程配置文件,这使得使用它非常的简便、直接。
这里我们以malloc函数为例,截获其他的函数方法与此类似。
需要被截获的函数可能在DLL中,也可能在程序的代码里。比如,如果静态连结C-Runtime Library,那么malloc函数的代码会被连结到程序里。为了截获住对这类函数的调用,BoundsChecker会动态修改这些函数的指令。
以下两段汇编代码,一段没有BoundsChecker介入,另一段则有BoundsChecker的介入:
126: _CRTIMP void * __cdecl malloc (
127: size_t nSize
128: )
129: {
00403C10 push ebp
00403C11 mov ebp,esp
130: return _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);
00403C13 push 0
00403C15 push 0
00403C17 push 1
00403C19 mov eax,[__n ......
BoundsChecker采用一种被称为 Code Injection的技术,来截获对分配内存和释放内存的函数的调用。简单地说,当你的程序开始运行时,BoundsChecker的DLL被自动载入进程的地址空间(这可以通过system-level的Hook实现),然后它会修改进程中对内存分配和释放的函数调用,让这些调用首先转入它的代码,然后再执行原来的代码。BoundsChecker在做这些动作的时,无须修改被调试程序的源代码或工程配置文件,这使得使用它非常的简便、直接。
这里我们以malloc函数为例,截获其他的函数方法与此类似。
需要被截获的函数可能在DLL中,也可能在程序的代码里。比如,如果静态连结C-Runtime Library,那么malloc函数的代码会被连结到程序里。为了截获住对这类函数的调用,BoundsChecker会动态修改这些函数的指令。
以下两段汇编代码,一段没有BoundsChecker介入,另一段则有BoundsChecker的介入:
126: _CRTIMP void * __cdecl malloc (
127: size_t nSize
128: )
129: {
00403C10 push ebp
00403C11 mov ebp,esp
130: return _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);
00403C13 push 0
00403C15 push 0
00403C17 push 1
00403C19 mov eax,[__n ......
fread函数和fwrite函数
1.函数功能
用来读写一个数据块。
2.一般调用形式
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
3.说明
(1)buffer:是一个指针,对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址。
(2)size:要读写的字节数;
(3)count:要进行读写多少个size字节的数据项;
(4)fp:文件型指针。
注意:1 完成次写操(fwrite())作后必须关闭流(fclose());
2 完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;
3 fprintf() : 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了。注意的是返回值为此次操作写入到文件的字节数。如int c = fprintf(fp, "%s %s %d %f", str1,str2, a, b) ;str1:10字节; ......
fread函数和fwrite函数
1.函数功能
用来读写一个数据块。
2.一般调用形式
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
3.说明
(1)buffer:是一个指针,对fread来说,它是读入数据的存放地址。对fwrite来说,是要输出数据的地址。
(2)size:要读写的字节数;
(3)count:要进行读写多少个size字节的数据项;
(4)fp:文件型指针。
注意:1 完成次写操(fwrite())作后必须关闭流(fclose());
2 完成一次读操作(fread())后,如果没有关闭流(fclose()),则指针(FILE * fp)自动向后移动前一次读写的长度,不关闭流继续下一次读操作则接着上次的输出继续输出;
3 fprintf() : 按格式输入到流,其原型是int fprintf(FILE *stream, const char *format[, argument, ...]);其用法和printf()相同,不过不是写到控制台,而是写到流罢了。注意的是返回值为此次操作写入到文件的字节数。如int c = fprintf(fp, "%s %s %d %f", str1,str2, a, b) ;str1:10字节; ......