Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Link error with really simple functions C++ on .h file

I've made two functions to 'cast' a 32/64 bit pointer into a double. The code worked when used alone (Just the .h and a .cpp including it) but when using the .h somewhere else (copied into the project directory and then included) ith throws 'already defined' error for all the functions on the .h file when linking.

the source code for the .h file is the following:

#pragma once
#ifndef __FLOATCAST_H
#define __FLOATCAST_H

//A quick and dirty way of casting pointers into doubles and back
//Should work with BOTH 64bit and 32bit pointers
union ptr_u {
    double d;
    void* p;
};

double ptr2double(void* pv){
    ptr_u ptr;
    ptr.p = pv;
    return (ptr.d);
};

void* double2ptr(double dv){
    ptr_u ptr;
    ptr.d = dv;
    return(ptr.p);
};

#endif

The link says the functions are already defined on a file source file (rather, his .obj) which does not include this one.

Edit: Why would I want a pointer-inside-double? Because I need Lua (5.1) to call-back an object member function.

Edit2: Lua provides a way of storing user data, it seems like the adequate soluton rather than casting the pointer (see comments)

like image 405
NeonMan Avatar asked Jun 21 '11 12:06

NeonMan


2 Answers

Mark your functions inline

inline double ptr2double(void* pv){
    ptr_u ptr;
    ptr.p = pv;
    return (ptr.d);
};

inline void* double2ptr(double dv){
    ptr_u ptr;
    ptr.d = dv;
    return(ptr.p);
};

You see, when you included the same function in two separate source files (translation units), you get multiple definitions. You have generally 2 options:

  • Have delrarations of your funcions in a .h file, and definitions in a separate .cpp file
  • Make your functions inline and keep them in a .h file

The One-Definition Rule of C++ prohibits multiple definitions of non-inline functions.

EDIT: The #ifdef guards guard against multiple inclusion into a single source file. But you can indeed include the .h file into different .cpp files. The ODR applies to definitions in the whole program, not just a single file.

EDIT2 After some comments I feel like I must incorporate this piece of information here lest there should be any misunderstanding. In C++ there are different rules concerning inline functions and non-inline ones, for example the special case of ODR. Now, you may mark any function (be it long or recursive, doesn't matter) as inline, and the special rules will apply to them. It is a completely different matter whether the compiler will decide to actually inline it (that is, substitute the code instead of a call), which it can do even if you don't mark the function as inline, and can decide not to do even if you mark it as inline.

like image 182
Armen Tsirunyan Avatar answered Nov 07 '22 14:11

Armen Tsirunyan


The canonical way to would be:

floatcast.h

#pragma once
#ifndef __FLOATCAST_H
#define __FLOATCAST_H

//A quick and dirty way of casting pointers into doubles and back
//Should work with BOTH 64bit and 32bit pointers
union ptr_u {
    double d;
    void* p;
};

double ptr2double(void* pv);
void* double2ptr(double dv);

#endif

floatcast.cpp

#include "floatcast.h"

double ptr2double(void* pv){
    ptr_u ptr;
    ptr.p = pv;
    return (ptr.d);
};

void* double2ptr(double dv){
    ptr_u ptr;
    ptr.d = dv;
    return(ptr.p);
};    
like image 43
sehe Avatar answered Nov 07 '22 14:11

sehe