0

At xdn-project/digitalnote ./src/crypto/crypto.cpp file there is an error at line 338 when compiling (using cmake):

return sizeof(rs_comm) + pubs_count * sizeof(rs_comm().ab[0]);
                                                     ^

error: value-initialization of incomplete type ‘Crypto::rs_comm:: []’

I found the solution on cryptonotefoundation/cryptonote:

return sizeof(rs_comm) + pubs_count * sizeof(((rs_comm*)0)->ab[0]);

I can play with Java JDK quite well, but currently at C++ need help :) It would be nice to see detail explanation of this code part:

sizeof(((rs_comm*)0)->ab[0]);

My questions are:

  1. Asterisk after rs_comm - what its for?
  2. 0) - what is the purpose of 0 here?

The fragment of code:

  struct rs_comm {
    Hash h;
    struct {
      EllipticCurvePoint a, b;
    } ab[];
  };

  static inline size_t rs_comm_size(size_t pubs_count) {
    return sizeof(rs_comm) + pubs_count * sizeof(rs_comm().ab[0]);
}
Ernestas Gruodis
  • 8,567
  • 14
  • 55
  • 117
  • 1
    It's a horrible hack that invokes *undefined behavior* – UnholySheep Mar 28 '18 at 15:10
  • Yes, I agree. But trying to figure it out. – Ernestas Gruodis Mar 28 '18 at 15:12
  • 1
    Where is undefined behaviour? – Zereges Mar 28 '18 at 15:13
  • 1
    It will return the size of the element of member `ab` of the struct `rs_common`. – Mohit Mar 28 '18 at 15:15
  • 2
    @UnholySheep It is not undefined behavior, it will work on every major c compiler. – Mohit Mar 28 '18 at 15:16
  • May be similar to [this question](https://stackoverflow.com/questions/3553296/c-sizeof-single-struct-member) – Mohit Mar 28 '18 at 15:23
  • 3
    @UnholySheep it would be undefined behaviour in an evaluated context, but it's the operand to `sizeof`, so it matters less – Caleth Mar 28 '18 at 15:26
  • 2
    Reading: [_Null Pointer Dereferencing Causes Undefined Behavior_](https://software.intel.com/en-us/blogs/2015/04/20/null-pointer-dereferencing-causes-undefined-behavior) by [Andrey Karpov](https://software.intel.com/en-us/user/308845) at software.intel.com/blogs, with an interesting exception just before the 'Acknowledgements' section. :) – CiaPan Mar 28 '18 at 15:37

3 Answers3

1

sizeof is an operator that return the size of a specific type. It can work directly with a type or with an expression.

This part (rs_comm*)0 is taking 0 (0 is a valid null pointer constant) and casting it to a pointer of the struct rs_comm (or the class, I don't know the definition of rs_comm, but I am guessing).

Now, it is accessing using the -> operator to the data-member ab. ab has to be define as array, so it can get the first item in the array.

Because, sizeof doesn't really evaluate the expression but just figuring out the type and get the size of it.

So, the final result is the size of the first element in the array ab for the class/struct rs_comm.

Alessandro Teruzzi
  • 3,918
  • 1
  • 27
  • 41
  • Being pedantic, `0` is **not** a pointer value. But it is a valid *null pointer constant*, and thus will be converted to a *null pointer value* in a pointer context. – Deduplicator Mar 28 '18 at 15:35
  • 1
    @Deduplicator be pedantic is useful with C++, thank, I have updated my answer – Alessandro Teruzzi Mar 29 '18 at 14:16
  • But according [this article](https://software.intel.com/en-us/blogs/2015/04/20/null-pointer-dereferencing-causes-undefined-behavior): _The pointer must be checked before being dereferenced_. Is this expression correct then: `sizeof(((rs_comm*)0)->ab[0])`? What is the simple way to check if `rs_comm` is `NULL` and if it is - return zero length, or if `rs_comm` was initialized - return the length of `ab[0]`? – Ernestas Gruodis Mar 30 '18 at 20:27
  • 1
    @ErnestasGruodis please, read the link of the sizeof documentation, you will found: "When applied to an expression, sizeof does not evaluate the expression, and even if the expression designates a polymorphic object, the result is the size of the static type of the expression." So, you don't need to check against the null pointer because the expression is not evaluated. – Alessandro Teruzzi Apr 02 '18 at 16:13
  • So, even if `rs_comm` is not declared anywhere, the expression `sizeof(((rs_comm*)0)->ab[0])` will get the size of inner structure `ab[0]`? That is the size of `EllipticCurvePoint a` plus `EllipticCurvePoint b`? – Ernestas Gruodis Apr 02 '18 at 18:55
1

So ab is an member of struct rs_comm, and is an array.

If you have a rs_comm object, i.e. rs_comm rs;, but you don't know the type of ab, you want to know its size, sizeof(rs.ab[0]) will do.

If you have a pointer to rs_comm, i.e. rs_comm *p_rs;, then sizeof(p_rs->ab[0]) will do the same thing.

If you don't have a rs_comm object nor a pointer to rs_comm, you can change a NULL pointer to a pointer to rs_comm, this is what ((rs_comm *)0) do.

Replace the p_rs in sizeof(p_rs->ab[0]) with ((rs_comm *)0), you get sizeof(((rs_comm *)0)->ab[0]).

bigeast
  • 627
  • 5
  • 14
0

sizeof(variable) . return the size variable data type . like char x ; cout << sizeof(x) ; the result would be