[C/C++标准库]_[初级]_[计算结构体成员的偏移量]

场景:

1. C结构体里计算结构体的偏移量平常看来没什么必要,但是放到插件结构的设计里就有必要了,比如只能使用偏移量访问的场景,而不能使用引用成员变量的场景。

2. 在设计一致性的接口时,公用的接口不怎么变化的,但是插件模块的结构可以不需要根据统一结构来设计,他们只需要提供偏移量给公用接口调用就行了,不同的插件

可能偏移量不一致,因为他们可以独立实现。公用接口就可以通过偏移量来访问不同的变量。

3. 可以使用stddef.h文件里的  offsetof

/* Define offsetof macro */
#ifdef __cplusplus

#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&reinterpret_cast<const volatile char&>((((s *)0)->m)) )
#else
#define offsetof(s,m)   (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
#endif

#else

#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

ffmpeg部分代码:

注意这里的OFFSET

static const AVOption options[]={
{"b", "set bitrate (in bits/s)", OFFSET(bit_rate), FF_OPT_TYPE_INT, AV_CODEC_DEFAULT_BITRATE, INT_MIN, INT_MAX, V|E},
{"ab", "set bitrate (in bits/s)", OFFSET(bit_rate), FF_OPT_TYPE_INT, 64*1000, INT_MIN, INT_MAX, A|E},
{"bt", "set video bitrate tolerance (in bits/s)", OFFSET(bit_rate_tolerance), FF_OPT_TYPE_INT, AV_CODEC_DEFAULT_BITRATE*20, 1, INT_MAX, V|E},
{"flags", NULL, OFFSET(flags), FF_OPT_TYPE_FLAGS, DEFAULT, 0, UINT_MAX, V|A|E|D, "flags"},
{"mv4", "use four motion vector by macroblock (mpeg4)", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_4MV, INT_MIN, INT_MAX, V|E, "flags"},
{"obmc", "use overlapped block motion compensation (h263+)", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_OBMC, INT_MIN, INT_MAX, V|E, "flags"},
{"qpel", "use 1/4 pel motion compensation", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_QPEL, INT_MIN, INT_MAX, V|E, "flags"},
{"loop", "use loop filter", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_LOOP_FILTER, INT_MIN, INT_MAX, V|E, "flags"},
{"qscale", "use fixed qscale", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_QSCALE, INT_MIN, INT_MAX, 0, "flags"},
{"gmc", "use gmc", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_GMC, INT_MIN, INT_MAX, V|E, "flags"},
{"mv0", "always try a mb with mv=<0,0>", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_MV0, INT_MIN, INT_MAX, V|E, "flags"},
{"part", "use data partitioning", 0, FF_OPT_TYPE_CONST, CODEC_FLAG_PART, INT_MIN, INT_MAX, V|E, "flags"},
{"input_preserved", NULL, 0, FF_OPT_TYPE_CONST, CODEC_FLAG_INPUT_PRESERVED, INT_MIN, INT_MAX, 0, "flags"},

测试代码,使用vs2010编译:

void TestOffset()
{
	//1.编译器会对结构体内数据类型自动对其类型大小值的倍数对齐.
	struct t
	{
		char c;
		char b;
		int e;
		int e1;
		double d;
	};

	cout << offsetof(t,b) << endl;
	cout << offsetof(t,e) << endl;
	cout << offsetof(t,e1) << endl;
	cout << offsetof(t,d) << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	TestOffset();

	return 0;
}

输出:

1
4
8
16
时间: 2024-10-10 12:24:35

[C/C++标准库]_[初级]_[计算结构体成员的偏移量]的相关文章

计算结构体首地址的技巧

struct ABC { int a; int b; int c; }; +----------+ <------我们需要计算的是这个地址. | a(4Byte) | +----------+ <------这个地址是已知的. | b(4Byte) | +----------+ | c(4Byte) | +----------+ 通过上图可看出,只需要把当前知道的成员变量的地址ptr,减去它在结构体当中相对偏移量(4),就得到了结构体的首地址(ptr-4). 设计一个type类型的结构体,起始

sizeof()计算结构体的大小

简要说明:结构体成员按照定义时的顺序依次存储在连续的内存空间,但是结构体的大小并不是简单的把所有成员大小相加,而是遵循一定的规则,需要考虑到系统在存储结构体变量时的地址对齐问题. 一.没有成员的结构体占用的空间是多少个字节? 答案是:1个字节. 这就是实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类或空结构体(C++中结构体也可看为类)隐含的加一个字节,这样空类或空结构体在实例化后在内存得到了独一无二的地址,所以空类所占的内存

[C/C++标准库]_[初级]_[交集和补集]

场景: 1. 计算std::vector A和 std::vector B里的相同的元素, 用于保留不删除. 2. 计算std::vector A和 std::vector B里各自的补集, 用于删除A的补集和添加B的补集,用在一些更新关联表的操作里. 比如联系人A所属分组B是一个集合BV, 把联系人A的所属分组 修改为集合CV, 就需要删除两个集合BV,CV的CV补集和新增BV补集. 3. C++标准库为我们提供了这些算法. 代码: // test_AndroidAssistant.cpp :

[C/C++标准库]_[初级]_[使用ctype里的isxxx函数时要注意的事项]

场景: 1. 标准库里的 ctype.h里的函数是用于1个字节的判断的,但是参数却是int, 这样很容易导致误用. isalpha iscntrl isdigit isgraph isprint ispunct isspace isxdigit isalnum islower isupper int isspace( int ch ); 最恶心的是vc++的实现会对超过1字节的值会直接崩溃,gcc不会!!! #if defined (_DEBUG) extern "C" int __c

[C/C++标准库]_[初级]_[使用模板删除字符串前后空格((w)string space)]

场景: 1. C++没有提供删除std::(w)string的前后空格的函数,比如TrimSpace. 2. 很多库都提供, 但是为了移植代码方便,最好还是能用标准库解决就用标准库. 下边用模板实现了移除空格的函数. test.cpp #include <iostream> #include <stdlib.h> #include <string.h> #include <string> #include <ctype.h> using name

[C/C++不常见语法特性]_[初级]_[左值-右值-lvalue-rvalue]

参考:1. http://en.cppreference.com/w/cpp/language/value_category   << Value categories >> 2. https://msdn.microsoft.com/en-us/library/dd293668.aspx   << Rvalue Reference Declarator: && >>3. https://msdn.microsoft.com/en-us/li

[zlib]_[初级]_[使用Zlib完整解压zip内容]

场景: 1. 解压文件一般用在下载了一个zip文件之后解压,或者分析某个文件需要解压的操作上. 2. 解压文件,特别是解压带文件夹的zip文件往往系统没有提供这类Win32 API,当然C#自带库能解压, 当然这里只讨论C/C++, 像C#和Java这种开挂的标准库不在考虑范围内. 3. zlib解压文件的使用例子在 contrib\minizip 例子里. 这里基本是直接提取miniunz.c 的代码进行封装解压即可, 只是改了下支持中文路径. 主文件 zip_util.cpp #includ

计算结构体大小

char类型的长度被定义为一个8位字节,这很简单. short类型的长度至少为两字节.在有些计算机上,对于有些编译程序,short类型的长度可能为4字节,或者更长. int类型是一个整数的“自然”大小,其长度至少为两字节,并且至少要和short类型一样长.在16位计算机上,int类型的长度可能为两字节:在32位计算机上,可能为4字节:当64位计算机流行起来后,int类型的长度可能会达到8字节.这里说的都是“可能”,例如,早期的Motorala 68000是一种16/32位的混合型计算机,依赖于不

[C/C++标准库]_[初级]_[如何实现std::string自己的Format(sprintf)函数]

场景: 1.  C语言有自己的sprintf函数,但是这个函数有个缺点,就是不知道需要创建多大的buffer, 这时候可以使用snprintf函数来计算大小,只要参数 buffer为NULL, count为0即可. 2.  这里实现std::string自己的sprintf也是用了snprintf的特性,先计算大小,再创建空间,之后存入std::string. 3.  还使用了C的可变参数特性. std::wstring Format(const wchar_t *format,...) { v