标签: offsetof

&((struct name*)NULL - > b)是否会在C11中导致未定义的行为?

代码示例:

struct name
{
    int a, b;
};

int main()
{
    &(((struct name *)NULL)->b);
}
Run Code Online (Sandbox Code Playgroud)

这是否会导致未定义的行为?我们可以辩论它是否"取消引用无效",但是C11没有定义术语"解除引用".

6.5.3.2/4明确指出*在空指针上使用会导致未定义的行为; 但它并没有说同样的->,也没有定义a -> b(*a).b; 它为每个运营商分别定义.

->6.5.2.3/4中的语义说:

后缀表达式后跟 - >运算符和标识符指定结构或联合对象的成员.该值是第一个表达式指向的对象的指定成员的值,并且是左值.

但是,NULL并没有指向一个对象,所以第二句似乎没有说明.

相关的可能是6.5.3.2/1:

约束:

一元运算&符的操作数应该是函数指示符,[]一元或一元运算*符的结果 ,或者是一个左值,它指定一个不是位字段的对象,并且不用寄存器存储类说明符声明.

但是我觉得粗体文本是有缺陷的并且应该读取可能指定对象的左值,按照6.3.2.1/1(左值的定义) - C99弄乱了左值的定义,所以C11必须重写它,也许这个部分错过了.

6.3.2.1/1确实说:

左值是一个表达式(对象类型不是void)可能指定一个对象; 如果左值在评估时未指定对象,则行为未定义

&操作员确实评估了它的操作数.(它不访问存储的值,但这是不同的).

这种长期推理似乎表明代码会导致UB,但它相当脆弱,我不清楚标准的作者是什么意图.如果事实上他们打算做任何事情,而不是让我们讨论:)

c offsetof language-lawyer c11

57
推荐指数
4
解决办法
3483
查看次数

是否有可能通过指向另一个未释放子对象的指针来获得一个子对象的指针?

看下面这个简单的代码:

struct Point {
    int x;
    int y;
};

void something(int *);

int main() {
    Point p{1, 2};

    something(&p.x);

    return p.y;
}
Run Code Online (Sandbox Code Playgroud)

我希望main可以将返回值优化为return 2;,因为something它无法访问p.y,只能返回的指针p.x

但是,没有一个主要的编译器会优化mainto 的返回值2上帝保佑

如果仅允许访问,标准中是否存在可以something修改的内容?如果是,这是否取决于标准布局?p.yp.xPoint

如果我使用something(&p.y);,该return p.x;怎么办?

c++ pointers offsetof language-lawyer c++17

51
推荐指数
1
解决办法
1397
查看次数

为什么不能在C++中的非POD结构上使用offsetof?

我正在研究如何在C++中将成员的内存偏移量转换为类,并在维基百科上看到了这一点:

在C++代码中,您不能使用offsetof来访问非Plain Data Data Structures的结构或类的成员.

我尝试了它似乎工作正常.

class Foo
{
private:
    int z;
    int func() {cout << "this is just filler" << endl; return 0;}

public: 
    int x;
    int y;
    Foo* f;

    bool returnTrue() { return false; }
};

int main()
{
    cout << offsetof(Foo, x)  << " " << offsetof(Foo, y) << " " << offsetof(Foo, f);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我收到了一些警告,但它已经编译,运行时它给出了合理的输出:

Laptop:test alex$ ./test
4 8 12
Run Code Online (Sandbox Code Playgroud)

我想我要么误解POD数据结构是什么,要么我错过了其他一些难题.我不知道问题是什么.

c++ offsetof

49
推荐指数
3
解决办法
2万
查看次数

为什么offsetof()的实现有效?

在ANSI C中,offsetof定义如下.

#define offsetof(st, m) \
    ((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
Run Code Online (Sandbox Code Playgroud)

为什么这不会引发分段错误,因为我们正在取消引用NULL指针?或者这是某种编译器黑客,它看到只有偏移的地址被取出,所以它静态地计算地址而不实际解除引用它?这个代码也可以移植吗?

c pointers offsetof

32
推荐指数
4
解决办法
2481
查看次数

在标准布局对象(例如,带有offsetof)内进行指针算术时,我们需要使用std :: launder吗?

该问题是针对以下问题的后续措施:当它实际上未指向char数组时,是否将其添加到“ char *”指针UB?

CWG 1314中,CWG确认使用指针在标准布局对象中执行指针算术是合法的unsigned char。这似乎意味着与链接的问题类似的某些代码应按预期工作:

struct Foo {
    float x, y, z;
};

Foo f;
unsigned char *p = reinterpret_cast<unsigned char*>(&f) + offsetof(Foo, z); // (*)
*reinterpret_cast<float*>(p) = 42.0f;
Run Code Online (Sandbox Code Playgroud)

(为了更清楚起见,我用替换charunsigned char。)

但是,似乎C ++ 17中的新更改意味着该代码现在是UB,除非std::launder在两个reinterpret_casts 之后都使用。reinterpret_cast两种指针类型之间的a结果等于两个static_casts:第一个为cv void*,第二个为目标指针类型。但是[expr.static.cast] / 13暗示这会生成指向原始对象的指针,而不是指向目标类型的对象的Foo指针,因为类型的对象不能与unsigned char对象的第一个字节进行指针互换,也不是一个unsigned char对象在的第一个字节f.z指针相互转换与f.z本身。

我很难相信委员会打算进行更改以打破这种非常普遍的习惯用法,从而使C ++ 17之前的所有用法都不offsetof确定。

c++ offsetof language-lawyer c++17

26
推荐指数
1
解决办法
454
查看次数

<stddef.h>中的'offsetof'宏是否会调用未定义的行为?

来自MSVC实施的示例:

#define offsetof(s,m) \
    (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))
//                                                   ^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

可以看出,它取消引用空指针,通常会调用未定义的行为.这是规则的例外还是正在发生的事情?

c++ offsetof undefined-behavior

18
推荐指数
2
解决办法
2273
查看次数

对于C++ 17中的非标准布局类,`offsetof`是"有条件支持"是什么意思?

C++ 17标准说:

[support.types.layout]

有条件地支持offsetof使用非标准布局类的宏.


[defns.cond.supp]

有条件地支持

程序构造不需要实现支持


我觉得这个定义offsetof不太精确.

  • 这是否意味着我可以安全地尝试在非标准布局类中使用它?

  • "条件支持"与实现定义有何不同?

  • 编译器是否不支持offsetof生成诊断所需的特定类型的类?

c++ offsetof language-lawyer c++17

15
推荐指数
1
解决办法
655
查看次数

C++ Compile-Time offsetof模板内部

我需要使用offsetoftemplate一个成员选择.如果您原谅尴尬的语法,我想出办法:

template <typename T,
          typename R,
          R T::*M
         >
constexpr std::size_t offset_of()
{
    return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
Run Code Online (Sandbox Code Playgroud)

用法并不完美(最好烦恼):

struct S
{
    int x;
    int y;
};

static_assert(offset_of<S, int, &S::x>() == 0, "");
static_assert(offset_of<S, int, &S::y>() == sizeof(int), "");
Run Code Online (Sandbox Code Playgroud)

constexpr形式更容易使用:

template <typename T, typename R>
std::size_t offset_of(R T::*M)
{
    return reinterpret_cast<std::size_t>(&(((T*)0)->*M));
};
Run Code Online (Sandbox Code Playgroud)

明显的缺点是它不是在编译时完成的(但更容易使用):

int main()
{
    std::cout << offset_of(&S::x) << std::endl;
    std::cout << offset_of(&S::y) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是语法constexpr品种,但仍然完全编译时间; 但是,我无法想出它的语法.我也很满意offset_of<&S::x>::value(就像其他类型特征一样),但无法弄清楚它的语法魔法.

c++ offsetof type-traits c++11

14
推荐指数
1
解决办法
6219
查看次数

使用offsetof访问结构体成员

我有以下代码:

#include <stddef.h>

int main() {
  struct X {
    int a;
    int b;
  } x = {0, 0};

  void *ptr = (char*)&x + offsetof(struct X, b);

  *(int*)ptr = 42;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

最后一行执行对 的间接访问x.b

该代码是根据任何 C 标准定义的吗?

我知道:

  • *(char*)ptr = 42;已定义,但仅定义了实现。
  • ptr == (void*)&x.b

我猜想访问ptrvia指向的数据int*不会违反严格的别名规则,但我不完全确定该标准保证了这一点。

c struct offsetof language-lawyer

14
推荐指数
1
解决办法
1197
查看次数

知道自己的偏移量的C++类成员变量

是否有可能有一个成员变量,它能够从指向自身的指针计算指向包含对象的指针(在它的方法中)?

让我们在API中包含一个外部调用接口,如下所示:

template <typename Class, MethodId Id, typename Signature>
class MethodProxy;

template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodProxy<Class, Id, ReturnT ()(Arg1T) {
  public:
    ReturnT operator()(Class &invocant, Arg1T arg1);
};
Run Code Online (Sandbox Code Playgroud)

类似地,对于从0到N的其他数量的参数.对于外来的每个类,一个C++类声明具有一些特征,并且该模板使用这些特征(以及参数类型的更多特征)来查找和调用外部方法.这可以像:

Foo foo;
MethodProxy<Foo, barId, void ()(int)> bar;
bar(foo, 5);
Run Code Online (Sandbox Code Playgroud)

现在我想做的是以Foo这种方式定义,我可以这样称呼:

Foo foo;
foo.bar(5);
Run Code Online (Sandbox Code Playgroud)

不重复签名多次.(显然创建一个静态成员并在方法中包装调用很简单,对吧).嗯,事实上,这仍然很容易:

template <typename Class, MethodId Id, typename Signature>
class MethodMember;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodMember<Class, Id, ReturnT ()(Arg1T) {
    MethodProxy<Class, Id, Signature> method;
    Class …
Run Code Online (Sandbox Code Playgroud)

c++ templates properties offsetof

11
推荐指数
1
解决办法
3082
查看次数