- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
简而言之,我的问题是:
C 标准明确规定结构成员的相对地址应该按照声明的顺序增长。它也没有说明结构成员应该如何精确对齐的任何细节。显然,这样做是为了允许填充结构和打包结构的实现。然而,从理论上讲,可以有一个符合标准的编译器,只要结构成员的增长顺序与成员声明的顺序相同,它就会为结构成员提供完全随机的地址。但是这样的编译器存在吗?
这里有一些细节。考虑以下两个结构:
struct s1 {
int var1;
char var2;
long var3;
};
struct s2 {
int var1;
char var2;
long var3;
char var4;
int var5;
};
和下面的代码:
printf("offsetof(struct s1, var2) = %d\n",
offsetof(struct s1, var2));
printf("offsetof(struct s2, var2) = %d\n",
offsetof(struct s2, var2));
printf("offsetof(struct s1, var3) = %d\n",
offsetof(struct s1, var3));
printf("offsetof(struct s2, var3) = %d\n",
offsetof(struct s2, var3));
gcc (GCC) 4.8.3 20140911 产生以下输出:
offsetof(struct s1, var2) = 4
offsetof(struct s2, var2) = 4
offsetof(struct s1, var3) = 8
offsetof(struct s2, var3) = 8
这非常有意义:一个常规的符合标准的编译器(不重新排序结构成员的编译器)在为结构成员执行填充时,只考虑前一个结构成员的大小和偏移量。这意味着具有相应类型的两个结构的第一个成员的相对地址在此类编译器上将始终相同。反过来,这意味着在我们的示例中,我们可以安全地执行以下操作:
struct s2 test_s2, *ptest_s2;
struct s1 test_s1, *ptest_s1;
ptest_s2 = &test_s2;
ptest_s1 = &test_s1;
ptest_s2->var1 = 1;
ptest_s2->var2 = '2';
ptest_s1 = (struct s1*)ptest_s2;
printf("ptest_s1->var1 = %d\n", ptest_s1->var1);
printf("ptest_s1->var2 = %c\n", ptest_s1->var2);
编译和运行良好,并在同一个编译器上给出输出
ptest_s1->var1 = 1
ptest_s1->var2 = 2
由于按照标准,所有指向结构的指针都具有相同的表示和对齐方式,因此这里 UB 的唯一来源实际上是期望具有相应类型的第一个结构成员的相对地址在两个结构中是相同的。
现在,真正的问题来了:现实世界中是否存在相对地址可能不同的编译器(那些不对结构成员重新排序的编译器)?
P.S. 我知道在 C11 中,我可以通过将第二个结构中的第一个结构的成员替换为第一个结构的匿名实例(其中,顺便说一句,据我所知,内部应该以相同的方式工作),但我想编写可以在不支持匿名结构的编译器版本上执行相同操作的代码。
最佳答案
这个问题出现的次数比您想象的要多。据我所知,答案是有条件的“否”。
共识似乎是编译器没有真正的理由填充成员,除了确保它们与它们的开始正确对齐并且可以占据数组中的连续位置。
标准要求第一个成员位于struct
的开头。
我只能找到相信以下是确定类型 T 对齐方式的最便携已知方法的人(在这里、网络等),并且没有人提供过不兼容的平台。
#include<stddef.h>
#define alignment(T) (offsetof(struct {char w;T v;},v))
编译器开发人员不会无缘无故地浪费内存。然而,从理论上讲,(比如说)有人可能决定将未对齐的成员放置在填充区域的末尾而不是开始处。甚至可以想象调试编译器可以在数组类型的末尾添加“覆盖标记”。
但是我找不到一个编译器的样本(或声明)(当不打包数据时)除了从第一个成员开始之外做任何事情,为下一个成员填充最少,然后为最严格对齐的成员结束填充。
然而,不同的编译器甚至在单一架构上也可能对基本类型做出不同的决定,因此即使在相同的硬件架构上,一个 struct
也可能具有不同的布局。
因此您不能依赖它来实现互操作性。
关于C - 非标准结构 "compatibility",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27835472/
我正在编写一个程序,它必须规范化音频 *.wav 文件。有一个“显示头部数据”的任务:ChunkId、ChunkSize 等等。 我想创建一个名为display_hdr 的函数(为了减少main.c
我有一个带有缩放类的 css 文件:1。 我在浏览器控制台上收到以下错误。 此页面使用非标准的“缩放”属性。相反,您可以将 calc() 或“transform”与“transform-origin:
我想模拟来自非标准密度函数的数据。我已经找到以下链接( How do I best simulate an arbitrary univariate random variate using its
使用已安装的 JDK 版本时,默认系统语言环境报告正确,但当我使用 adoptopenjdk-11 时tar.gz ,总是报告为en_US import java.util.Locale; publi
我如何强制 automake 为非标准 C++ 后缀文件生成依赖项跟踪?特别是我的意思是生成 .deps 目录文件内容。我也在使用 libtool。 谢谢 最佳答案 看看this section in
我有一个快速解决方法的问题,以享受非标准 gnu 的好处 case ranges .例如,非标准: case 1 ... 5: 可以替换为: case 1: case 2: case 3: case
我有两个“日期”字段需要加入。 第一个是格式为 yyyy-mm-dd hh:mm:ss 的普通日期时间 第二个是红头步骤子格式的 varchar(8) mmddyyyy 现在这变得很痛苦,因为没有简单
我有一个符合以下约定的 CSV val1,val2,outerStruct1{valA,valB,innerStruct2{valX, valY},valC},... 问题是当我尝试正则表达式oute
我有数据列: id name type number 1 n1 t1 num1 2 n2 t1 num2 3 n3 t1 num3 4
我正在为 Shelly 系列设备开发 openHAB2 绑定(bind)。 http接口(interface)运行良好,但无法注册获取COAP事件。 有人有使用 Californium 框架的经验吗?
我在 UILabel 上显示商标“TM”字符时遇到了一些问题。 出现问题的“TM”字符是\U0099 而不是通常的\U2122 稍微深挖一下,发现“TM”字\U0099属于极少数的汉字。 所以我猜 i
请原谅我的无知,我是 c++ 的新手。 完整错误信息: coog.cpp(74): error C3867: 'Manager::start_foo': 非标准语法;使用“&”创建指向成员的指针 我正
我有一个可以生成如下 JSON 的 API: )]}', { //JSON DATA } //JSON DATA 是有效的 JSON,但顶部的 )]}', 不是。 当我尝试通过逻辑应用获取此数
我尝试使用 Apache Ant Get task获取我们公司另一个团队生成的 WSDL 列表。他们将它们托管在 http://....com:7925/services/ 上的 weblogic 9
我在 Google App Engine 上有一个 servlet,它从页面获取文本,将其存储为实体,然后将其发送回客户端。当我存储“You're”一词时,它会像平常一样在 GAE 本地存储中显示为“
这个问题在这里已经有了答案: Is there a way to access the underlying container of STL container adaptors? (10 个答案
我在编译这段代码时遇到了问题: void MyClass::MyMethod(Type * new_ptr) { myInternalUniquePtr_->swap(std::unique_
我有两个 Eigen::VectorXd 对象,A 和 B,具有相同的维度 n。 我想创建一个新的 vector C,这样: 如果 B[i] 是 NaN,则 C[i] = A[i] 否则:C[i] =
在 C++ 中,以这种格式向日期添加一天的最简单方法是什么: “20090629-05:57:43” 可能使用 Boost 1.36 - Boost::date、Boost::posix_date 或
我正在使用 Apache HTTPComponents 4.3 的 HttpCore 库编写一个 HTTP 服务器( java )。我的服务器必须能够接收具有非标准 HTTP 方法(GET、POST、
我是一名优秀的程序员,十分优秀!