My code may be crashing because the 'class'

2019-09-12 00:23发布

-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*),"");

3条回答
姐就是有狂的资本
2楼-- · 2019-09-12 00:55
  • 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!

查看更多
叛逆
3楼-- · 2019-09-12 00:59

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.

查看更多
Luminary・发光体
4楼-- · 2019-09-12 01:05
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.

查看更多
登录 后发表回答