不管代码有多“糟糕”,并且假设对齐等在编译器/平台上不是问题,这种行为是未定义的还是损坏的?
如果我有这样的结构:-
struct data
{
int a, b, c;
};
struct data thing;
将 a
、b
和 c
访问为 (
在每一种情况下,在我尝试的每一个编译器和平台上,我尝试的每个设置都“有效”。我只是担心编译器可能没有意识到b和thing[1]是同一个东西,存储到“b”的可能被放入寄存器,thing[1]从内存中读取错误的值(例如)。但在每一种情况下,我都尝试过,但都做了正确的事情。(我当然意识到这并没有太多证明)
这不是我的代码;这是我必须处理的代码,我对这是坏代码还是坏代码感兴趣,因为不同会影响我更改它的优先级:)
标记为C和C。我最感兴趣的是C,但如果C不同,也是C,只是为了兴趣。
在C中如果真的需要的话——创建操作符[]:
struct data
{
int a, b, c;
int &operator[]( size_t idx ) {
switch( idx ) {
case 0 : return a;
case 1 : return b;
case 2 : return c;
default: throw std::runtime_error( "bad index" );
}
}
};
data d;
d[0] = 123; // assign 123 to data.a
它不仅保证工作,而且用法更简单,您无需编写不可读的表达式(
注意:给出这个答案的前提是假设您已经有一个带字段的结构,并且您需要通过索引添加访问。如果速度是一个问题,您可以改变结构,这可能会更有效:
struct data
{
int array[3];
int &a = array[0];
int &b = array[1];
int &c = array[2];
};
这个解决方案将改变结构的大小,因此您也可以使用方法:
struct data
{
int array[3];
int &a() { return array[0]; }
int &b() { return array[1]; }
int &c() { return array[2]; }
};
不。在C中,即使没有填充,这也是未定义的行为。
导致未定义行为的原因是越界访问1。当您有一个标量(结构中的成员a、b、c)并尝试将其用作数组2来访问下一个假设元素时,您会导致未定义行为,即使该地址碰巧有另一个相同类型的对象。
但是,您可以使用结构对象的地址并计算到特定成员中的偏移量:
struct data thing = { 0 };
char* p = ( char* )&thing + offsetof( thing , b );
int* b = ( int* )p;
*b = 123;
assert( thing.b == 123 );
这必须对每个成员单独执行,但可以放入类似数组访问的函数中。
< sup>1(引自:ISO/innux 6 . 5 . 6加法运算符8)
如果结果比数组对象的最后一个元素多一位,则它不能用作一元*运算符的操作数。
< sup>2(引自:ISO/x 6 . 5 . 6加法运算符7)
对于这些运算符,指向非数组元素的对象的指针的行为与指向长度为1的数组的第一个元素的指针的行为相同,其元素类型为对象的类型。
这是非法的1。这是C语言中未定义的行为。
您以数组的方式获取成员,但这是C标准所说的(强调我的):
[数氯阵列/1]: ...数组类型的对象包含一个连续分配的非空 N 个子对象集,这些子对象类型为 T...
但是,对于成员来说,没有这样的连续要求:
[class.mem/17]:…;实现对齐要求可能会导致两个相邻的成员不会立即在彼此之后分配…
虽然上面的两个引号应该足以说明为什么像你一样索引到结构
中不是C标准定义的行为,但让我们选择一个例子:看看表达式(
[expr.post//expr.sub/1]:后缀表达式后跟方括号中的表达式是后缀表达式。其中一个表达式应该是“T数组”类型的glvalue或“T指针”类型的prvalue,另一个应该是无作用域枚举或整数类型的prvalue。结果是“T”类型。“T”类型应该是完全定义的对象类型。66表达式
E1[E2]
(根据定义)与((E1)(E2))
相同
深入研究上面引用的粗体文本:关于向指针类型添加整数类型(注意此处的强调)。
[expr.add/4]:当具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果表达式
P
指向具有n个元素的数组对象x
的元素x[i]
,则表达式P J
和J P
(其中J
具有值j
)指向(可能是假设的)元素x[i j]
if0≤i j≤n
;否则,行为未定义。…
注意if子句的数组要求;否则在上面的引号中。表达式
(
附带说明:虽然我已经在各种编译器上对代码及其变体进行了广泛的实验,并且他们没有在这里引入任何填充,(它有效);从维护的角度来看,代码非常脆弱。您仍然应该断言实现在执行此操作之前连续分配了成员。并保持在边界内:-)。但它仍然是未定义的行为……
其他答案已经提供了一些可行的解决方法(具有已定义的行为)。
正如我在评论中正确指出的那样,我之前编辑的[basic.lval/8]不适用。谢谢@2501和@M.M。
1:请参阅@Barry对这个问题的回答,这是唯一一个可以通过此部分访问
事物
结构成员的法律案例。
a rt_alarm_container rt_i2c_bus_device rt_pm_ops rt_timer rt_alarm_setup rt_i2c_bus_device_ops rt_pwm_configuration rt_uart_ops addrinfo rt_completion rt_i2c_msg r
主要内容:引子,一、索引,二、mysql中索引的数据结构,三、源码,五、总结引子 说几句题外话,在京被困三个月之久,不能回家,所以这个源码分析就中断了。之所以在家搞这个数据库的源码分析,主要是在家环境齐全,公司的电脑老旧不堪。意外事件往往打断正常的习惯和运行轨迹,但这却是正常现象。回来也有两周,从本周开始恢复这个源码分析的系列。 大德久远,有始有终! 一、索引 什么是索引?索引有什么作用?还记得上小学时,老是教使用字典么?如果一个字不认识或者知道读音但字儿不会写都可以通过
我想将多个结构列合并成一个数组。 我从..尝试了数组(col1,col2),但结果是数据类型不匹配,即使所有结构列都是相同的类型。 查询- < code > select array(struct(f_name _ add,True as is_data_found),struct(l_name_add,True as is_data_found))作为标记from (select array(m
在 Solidity 中,合约类似于面向对象编程语言中的类。 每个合约中可以包含 状态变量、 函数、 函数修饰器、事件、 结构类型、 和 枚举类型 的声明,且合约可以从其他合约继承。 状态变量 状态变量是永久地存储在合约存储中的值。 pragma solidity ^0.4.0; contract SimpleStorage { uint storedData; // 状态变量
问题内容: 我有一个在轴1(列)中具有层次结构索引的数据框(来自操作): 我想将其展平,使其看起来像这样(名称不是关键的,我可以重命名): 我该怎么做呢?(我已经尝试了很多,无济于事。) 根据建议,这是字典形式的头 问题答案: 我认为最简单的方法是将列设置为顶级: 注意:如果to级别具有名称,你也可以通过此名称访问它,而不是0。 如果要将 组合成一个索引(假设你的列中仅包含字符串条目),则可以:
本文向大家介绍MySQL联合索引用法示例,包括了MySQL联合索引用法示例的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了MySQL联合索引。分享给大家供大家参考,具体如下: 员工表 userid 部门表 deptid 员工部门表 条件:一个员工可以对应多个部门 问题:怎么样设置数据库,让其不能重复添加 userid 和deptid? uuid userid deptid 111 212