2017-04-19 61 views
2

我的C++头是C包装为C++类返回不正确的地址

header.hh

#include <stdint.h> 
#include <stdio.h> 
#ifdef __cplusplus 
#include <string> 
class A 
{ 
    uint32_t a; 
    public: 
     A(){ 
      a = 0; 
     } 
     void update(uint32_t b) { 
      a = b; 
     } 
}; 
#else 
typedef struct A A; 
#endif //__cplusplus 
#ifdef __cplusplus 
extern "C" { 
    void* newA(void); 
    void deleteA(A* a); 
    void update(A*a,uint32_t b); 
} 
#endif 

而我的C++文件是

class.cc

#include "header.hh" 
#include <iostream> 
extern "C" { 
    void* newA(void) { 
     A* a = new A(); 
     return (reinterpret_cast <void*> (a)); 
    } 
    void deleteA(A* a) { 
     delete a; 
    } 
    void update(A* a,uint32_t b){ 
     a->update(b); 
    } 
} 

main.c中

#include "header.hh" 
#include <stdio.h> 
int main() 
{ 
    A* a = (A*) newA(); 
    deleteA(a); 
} 

的Makefile

CFLAGS=-Wall -g -ansi -pedantic -std=c99 
CCFLAGS=-Wall -g 
LDFLAGS=-g -Wall -lstdc++ 

OBJS=class.o main.o 
PROG=test 

all:$(PROG) 
default: all 

%.o: %.cc 
    $(CC) $(CCFLAGS) -c $< 

%.o: %.c 
    $(CC) $(CFLAGS) -c $< 

$(PROG): $(OBJS) 
    $(CC) $(OBJS) $(LDFLAGS) -o [email protected] 

clean: 
    rm -rf $(OBJS) 
    rm -rf $(PROF) 

当我编译并运行这个程序,我看到了段错误,当我尝试调用主析构函数。

我走进GDB,发现地址“一”在class.cc是0x7fff980097a0并在主要是0xffffffff980097a0

什么导致地址被改变?

我在ubuntu 14.04上使用gcc的4.8.4版本。

+0

顺便说一句,你可能会返回'A的*'代替'无效*'为'newA'。 – Jarod42

回答

5

当你编译的main.c与C编译器,它不会为newAdeleteAupdate函数的声明(他们与#ifdef __cplusplus包围)。

所以,它会假设默认的签名int newA()(其他两个类似)。

这意味着,在这行:

A* a = (A*) newA(); 

newA()返回的值被视为int,然后浇铸到A*。将int转换为指针类型的结果是实现定义的。在你的平台上,看起来你的行为就是你观察到的。

最有可能的是,在您的平台上,sizeof(int)4,而sizeof(void*)8。在这种情况下,当作为处理int0x7fff980097a0被截断为0x980097a0,然后浇铸到A*当扩展到0xffffffff980097a0。这正是你所观察到的。

相反,尝试本作的声明可见的C编译器:

#ifdef __cplusplus 
extern "C" { 
#endif 
    void* newA(void); 
    void deleteA(A* a); 
    void update(A*a,uint32_t b); 
#ifdef __cplusplus 
} 
#endif 
+0

好的,那么我该如何解决这个问题? – Tchinmai

+0

'main.c'如何编译? –

+0

@Tchinmai:更新了我的答案以包含解决方案。 –

1

在标题:

#ifdef __cplusplus 
extern "C" { 
#endif 

// The header declaration is included both by the the C and the C++ 
// compiler. 

void* newA(void); 
void deleteA(A* a); 
void update(A*a,uint32_t b); 

#ifdef __cplusplus 
} 
#endif