admin管理员组文章数量:1317914
Let's say I have a type in a header, used by C/C++-code, looking like this:
typedef struct Point
{
double X, Y, Z;
} Point ;
It is usually allocated on the stack, like this.
Point point;
memset(&point, 0, sizeof(point));
This initialization is mostly performed in C++-code, and only rarely in C-code. The C-code still needs to know about this type, however, as the C-code performs operations on it.
e.g.
C_API void mutatePoint(Point *point);
My question is therefore, would it be safe to add a conditional C++-constructor, to avoid having to call memset every time?
typedef struct Point
{
double X, Y, Z;
#ifdef __cplusplus
Point() { X = Y = Z = 0.0; }
Point(double x, double y, double z) { X = x; Y = y; Z = z; }
#endif
} Point;
This would simplify initialization and usage in C++-code:
Point point;
mutatePoint(&point); // Already set to (0, 0, 0) due to constructor, no need to memset first
When I talk about safe, I mean does it violate any C/C++-rules such as ODR? Or would this be OK to do. I'm OK with it not being recommended, and I'm also OK with hearing any inputs on why it would it would not be recommended.
But I'm mainly wondering whether or not there's a rule that explicitly allows/disallows this. I can confirm that such code compiled with msvc works seemingly ok, and has done so for many years.
Let's say I have a type in a header, used by C/C++-code, looking like this:
typedef struct Point
{
double X, Y, Z;
} Point ;
It is usually allocated on the stack, like this.
Point point;
memset(&point, 0, sizeof(point));
This initialization is mostly performed in C++-code, and only rarely in C-code. The C-code still needs to know about this type, however, as the C-code performs operations on it.
e.g.
C_API void mutatePoint(Point *point);
My question is therefore, would it be safe to add a conditional C++-constructor, to avoid having to call memset every time?
typedef struct Point
{
double X, Y, Z;
#ifdef __cplusplus
Point() { X = Y = Z = 0.0; }
Point(double x, double y, double z) { X = x; Y = y; Z = z; }
#endif
} Point;
This would simplify initialization and usage in C++-code:
Point point;
mutatePoint(&point); // Already set to (0, 0, 0) due to constructor, no need to memset first
When I talk about safe, I mean does it violate any C/C++-rules such as ODR? Or would this be OK to do. I'm OK with it not being recommended, and I'm also OK with hearing any inputs on why it would it would not be recommended.
But I'm mainly wondering whether or not there's a rule that explicitly allows/disallows this. I can confirm that such code compiled with msvc works seemingly ok, and has done so for many years.
Share Improve this question edited Jan 24 at 15:55 3CxEZiVlQ 39.1k11 gold badges80 silver badges92 bronze badges asked Jan 24 at 12:57 Bård Sigurd MøllerBård Sigurd Møller 213 bronze badges 4 |1 Answer
Reset to default 4it is safe, it is not illegal. since all C++ translation units see the same code, there is no ODR violations. but it is very confusing when the same code has different behavior when compiled with a C++ and a C compiler.
in C++ you can zero initialize a struct as follows.
Point point{}; // zero (value) initialized
Point point; // uninitialized
other ways to have a good C++ API method is that you can make the C++ type inherit the C type, as mentioned by @Ted Lyngmo in the comments and as done by microsoft in CPoint.
typedef struct Point
{
double X, Y, Z;
} Point ;
void mutate_point(Point*); // C API
struct CPoint : public Point
{
CPoint() : Point{} {}
CPoint(const Point& p) : Point{ p } {}
CPoint(double x, double y, double z) : Point{ x,y,z } {}
void mutate() { mutate_point(this); }
};
int main()
{
Point b = CPoint(); // compiles!
CPoint c;
mutate_point(&c); // also compiles
}
Another is declaring a C++ wrapper type with an implicit conversion operator to a reference to the C type, similar to vulkan-hpp (but not equivalent, what they actually do is UB, this is not)
struct CPoint
{
Point p{};
operator Point& () { return p; }
operator const Point& () const { return p; }
void mutate() { mutate_point(&p); }
};
Point b = CPoint(); // compiles!
you can get mutate_point(CPoint&)
to compile using ADL if you really want it.
本文标签: visual cIs it safe to conditionally add constructors to a class used in both C and CStack Overflow
版权声明:本文标题:visual c++ - Is it safe to conditionally add constructors to a class used in both C++ and C? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742023636a2415140.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Point point{};
to get an initialized version andPoint point;
when you want it uninitialized .... why confuse other c++ users ? What i see also done is wrapping it in a c++ type with an implicit conversion operator to a reference to the C type, so the two can be used interchangeably – Ahmed AEK Commented Jan 24 at 13:03struct Point p = {0};
(you can omit the0
from C24 onwards). This initializes, recursively if needed, all members of the struct to zero of the right kind (0
for int;0.0
for double;NULL
for pointers; etc). ... No need formemset
! – pmg Commented Jan 24 at 13:11Point
in C++ and provide whatever member functions you want. – Ted Lyngmo Commented Jan 24 at 13:18struct
. You're skirting UB in both languages (same requirements for twostruct
definitions to be considered the same - essentially, the definition is made up of identical sets of tokens). It's quite feasible for some future programmer (maybe yourself) maintaining your code being confused by your approach and unintentionally introducing UB. Better to do something like Ted suggested (so both C and C++ code see the samestruct
definition). – Peter Commented Jan 24 at 22:27