2

There was a bug in g++-4.1 and prior which made it reject the following valid program:

struct S { int n; };
unsigned long long f() { return sizeof S::n; }
    // ^--g++-4.1 "error: invalid use of non-static data member 'S::n'"
int main() {}

I need to write portable code to be compiled (among others) with this old version of g++, so I came up with the following:

#define sizeofmember(type, member) sizeof(static_cast<type*>(0)->member)
unsigned long long f() { return sizeofmember(S,n); }

I know that the crafted type* NULL pointer won't be dereferenced, because of:

[expr.sizeof]/1

The sizeof operator yields the number of bytes occupied by [...] the type of its operand. The operand is either an expression, which is an unevaluated operand ([expr.prop]), or a parenthesized type-id.

[expr.context]/1

In some contexts, unevaluated operands appear ([expr.prim.req], [expr.typeid], [expr.sizeof], [expr.unary.noexcept], [dcl.type.simple], [temp]). An unevaluated operand is not evaluated. [ Note: In an unevaluated operand, a non-static class member may be named ([expr.prim.id]) and naming of objects or functions does not, by itself, require that a definition be provided ([basic.def.odr]). An unevaluated operand is considered a full-expression. — end note ]

But is it valid though? From C++98 to C++14?

Community
  • 1
  • 1
YSC
  • 38,212
  • 9
  • 96
  • 149
  • I think we had the same discussion about `offsetoff` and reached the conclusion that it isn't. – Baum mit Augen Jul 30 '18 at 15:57
  • @anatolyg That isn't a direct answer. – Passer By Jul 30 '18 at 15:59
  • @anatolyg Yeah, that's what I'm talking about. *However*, it's not a dupe IMO because different rules apply to user code vs code in the implementation. "Quod licet Jovi, non licet bovi", as AnT put it. – Baum mit Augen Jul 30 '18 at 15:59
  • 4
    related/dupe: https://stackoverflow.com/questions/7721184/is-sizeofptr-undefined-behavior-when-pointing-to-invalid-memory and https://stackoverflow.com/questions/13574421/why-doesnt-my-program-seg-fault-when-i-dereference-a-null-pointer-inside-of-mal – NathanOliver Jul 30 '18 at 15:59
  • @BaummitAugen Most implementations of `offsetof` involves a value computation of the member, while an unevaluated context doesn't. – Passer By Jul 30 '18 at 16:00
  • @PasserBy Yeah, I'm explicitly saying it's *not* a dupe, but I think there were some arguments about dereferencing a null pointer in various contexts there. But no time to check in detail atm. – Baum mit Augen Jul 30 '18 at 16:01
  • I find the first suggestion by @NathanOliver quite convincing. The double tagging is unfortunate, though. – Baum mit Augen Jul 30 '18 at 16:05
  • Fortunately the answer has an explicit section for C++. – Passer By Jul 30 '18 at 16:05
  • @PasserBy that last suggested dup doesn't add anything to my question, though :/ – YSC Jul 30 '18 at 16:07
  • You mean the second one by NathanOliver? I agree to some extent? It's tagged as C after all, although the logic is the same in both languages. – Passer By Jul 30 '18 at 16:08
  • @PasserBy No, the first one (https://stackoverflow.com/a/7721284/5470596). – YSC Jul 30 '18 at 16:08
  • 2
    @YSC Whether the answers are great and whether it's the same question are two different questions. Closing this and answering the other one with a better answer is more useful than leaving the target halve answered – Baum mit Augen Jul 30 '18 at 16:09
  • @BaummitAugen That would be disappointing if it was all there were to say. I agree with your last sentence, of course. But there is a worse alternative: closing that question and letting the other one untouched. – YSC Jul 30 '18 at 16:12
  • @YSC Ah ok. Well, bounty it if needed. We are rich enough. – Baum mit Augen Jul 30 '18 at 16:14
  • @BaummitAugen It would be disappointing if there were no normative part of the standard saying this is well defined. But if it is the case, then yes this question cannot be answered differently than "Yes". – YSC Jul 30 '18 at 16:14
  • @YSC AFAIK, there is no normative part except from stitching together the two sections of the standard like you have already done. – NathanOliver Jul 30 '18 at 16:18
  • 1
    @BaummitAugen that's true, done! – YSC Jul 30 '18 at 16:24
  • 2
    I don't understand this question. Why do you think that it may not be "valid"? Parameter to sizeof is not evaluated, its type what matters only. – geza Jul 31 '18 at 08:28
  • `offsetof` has nothing to do with this question – M.M Aug 05 '18 at 01:41
  • @geza And what's the type of a dereferenced null pointer? – YSC Aug 05 '18 at 11:04
  • 2
    @YSC: if you have a pointer `p` of type `T *`, then `sizeof(*p)` equals to `sizeof(T)`. It doesn't matter whether `p` is null or not. The type of the expression matters, the expression itself is not evaluated. – geza Aug 05 '18 at 11:09
  • I guess you meant `return sizeofmember(S,n);` rather than `return sizeof sizeofmember(S,n);` – M.M Aug 06 '18 at 10:37
  • @M.M indeed ;). – YSC Aug 06 '18 at 11:20
  • @BaummitAugen As a matter of fact, my question is precisely [issue 323 of the Standard](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232), which is unsettled. Thank you for your time and opinions, it was valuable to me. – YSC Sep 12 '18 at 09:40

0 Answers0