My code may be crashing because the 'class' isn't C compatible?

十年热恋 提交于 2019-12-12 02:53:39

问题


-edit- I narrowed it down. Reproducible: Why does passing this object in C break my code?

My app is not working properly after i made a change. I got a warning in msvc but not in gcc. Heres a repo of the warning.

warning C4190: 'fnA' has C-linkage specified, but returns UDT 'Test' which is incompatible with C

#include <type_traits> 

template<class T>
class Test{
        T t;
};
typedef Test<int> A;
//static_assert(std::is_pod<A>::value, "Not a POD"); //fails in msvc 2010
static_assert(sizeof(A) == sizeof(int), "");
static_assert(sizeof(A) == sizeof(void*), "");
extern "C" {
        A fnA(A v) { return v; }
}
int main() {
        A a;
        fnA(a);
}

AFAIK there should be no reason why i can't use Test as a return value; This may not be the problem but this may be the problem. I can't figure out the problem but i get runtime oddities that i can not reproduce (both gcc and msvc). I suspected the problem would be MyString is corrupted but it appears that isnt the case which made me quite confused. Heres my wrapper. MyString is >8bytes and i need to hand this off to C code which returns everything by int unfortunately. Which is why i put the static assert to see if the class size is what i expected. Now that size/splicing is handled, i'm still completely like WTF!?! Why does that warning exist and is there anything i can possibly do to fix it?

Even writing class Test{ T t; }; causes the warning however struct fixes it. struct with private breaks it and i need t to be private.

OK! After I removed the constructors in WrappedPointer and changed the class to struct (which makes lhs public). It runs perfectly in GCC and MSVC. Changing struct WrappedPointer to class WrappedPointer breaks my code. WTF!?! This is a debug build too, not optimized. Why on earth does changing the keyword struct to class break the code!?! WTF!?! BUT that change doesnt break gcc. Using non default constructors break gcc...

template <class T>
struct WrappedPointer {
//private:
    T* lhs;
public:
    void SetLHS(T*v) { lhs=v; }
    //WrappedPointer(){}
    //WrappedPointer(T*value) : lhs(value){}
    //WrappedPointer(const WrappedPointer&v) : lhs(v.lhs){}
    T* operator->() const { return lhs; }
    T* operator*() const { return lhs; }
    template<class TT>
    bool operator==(TT t) const { return *lhs==t; }
    template<class TT>
    bool operator!=(TT t) const { return *lhs!=t; }

    bool operator==(int v) const { myassert2(v==0); return lhs==0; }
    bool operator!=(int v) const { myassert2(v==0); return lhs!=0; }
    bool operator==(const WrappedPointer&t) const { return *lhs==*t; }
    bool operator!=(const WrappedPointer&t) const { return *lhs!=*t; }
}
typedef WrappedPointer<MyString> String;
//typedef MyString* String;
static_assert(sizeof(String) == sizeof(int), "");
static_assert(sizeof(String) == sizeof(void*),"");

回答1:


The external "C" marks the function to have C linkage and disables name mangling. Now the issue in your function is that the argument is a template (the typedef only creates an alias in the current translation unit, A is still Test<int> for all purposes), and that name must be mangled.




回答2:


extern "C" {
    A fnA(A v) { return v; }
}

This says that fnA is a C function. C does not have object-oriented programming, or templates. The function uses both. Therefore, it cannot link as a C function.




回答3:


  • Classes are not valid in C.
  • Templates are not valid in C.
  • Templated classes are certainly not valid in C.

Pick your language and stick to it!



来源:https://stackoverflow.com/questions/9628663/my-code-may-be-crashing-because-the-class-isnt-c-compatible

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!