6

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)

NeonMan
  • 623
  • 10
  • 24
  • 2
    Casting a pointer to a double sounds like a disaster waiting to happen. Look up "light userdata" in Lua. – interjay Jun 21 '11 at 12:10
  • I'm just starting to use the Lua C api and it simply flew over me. I'l take a look since this seems like the real solution. (I knew the double-casting was a klutz, but it worked ;) – NeonMan Jun 21 '11 at 12:32
  • agree with @interjay - only "user data" – Jacek Cz Apr 12 '16 at 05:31

4 Answers4

10

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.

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • It worked, but why? the .h contents are protected by the #ifdef preprocesor commands. What if I can't make a function inline? (ie recursive) Edit: I assume then i need a separate .cpp – NeonMan Jun 21 '11 at 12:09
  • As interjay said on other answer, STL (and a template I made) does have code in the .h but doesn't need to be inlined. – NeonMan Jun 21 '11 at 12:11
  • @NeonMan: Templates have other rules than non-templates. most of STL code is class templates and function templates – Armen Tsirunyan Jun 21 '11 at 12:12
  • What does inline have to do with recursion? But if you can't make it inline, just do what sehe proposed. – RedX Jun 21 '11 at 12:14
  • @RedX: You can mark ANY function as inline - whether it is recursive or not. And you can and should have multiple definitions **regardless** of whether the function will actually be inlined by the compiler or not – Armen Tsirunyan Jun 21 '11 at 12:15
  • @RedX: Note that marking the function as inline will not necessarily guarantee it will be inlined, but all the syntactic and semantic rules of inline functions will hold regardless of the decision of the compiler – Armen Tsirunyan Jun 21 '11 at 12:17
  • @RedX You can't inline-expand a recursive function. This functions can be made inline easily (and makes some sense since the code is short and used frequently) but thans @Armen Tsirunyan to explain why it does work. – NeonMan Jun 21 '11 at 12:18
  • I would suggest splitting into a .h with prototypes and a .cpp with code is the better option, and let the compiler decide whether to perform the inlining optimization, but this answer has a lot of good information. – qid Jun 21 '11 at 12:19
  • @NeonMan See this: http://stackoverflow.com/questions/190232/can-a-recursive-function-be-inline – RedX Jun 21 '11 at 12:23
  • @qid Afaik functions can only be inlined if the linker knows their code (at least that's what i have always been taught, not counting Whole Program Optimization and similar). http://yosefk.com/c++fqa/inline.html#fqa-9.1 (Around the middle of this section) – RedX Jun 21 '11 at 12:26
3

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);
};    
sehe
  • 374,641
  • 47
  • 450
  • 633
0

Put your code in a .cpp file and in the .h file just put the prototypes -

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

Or keep the code as it is and add "inline" to each function definition which will allow you to define them in each module

Although I don't think that your code will actually do anything very useful. it's undefined behavour to access a different member of a union than the one you used to store the data. Plus even if that "worked" I can't think how you plan to use this, you'll store a double and read 32 bits of it into a pointer (on a 32 bit machine)... How can you possibly make use of this for anything?

jcoder
  • 29,554
  • 19
  • 87
  • 130
  • A workarroud to pass pointers for Lua to call back (long to explain) since lua's only numeric type is double – NeonMan Jun 21 '11 at 12:13
  • Ah ok, you're only storing pointers in doubles, not the other way round. Still dodgy, but might work in practice. Doesn't lua have some concept of "userdata" for storing this kind of thing? It's a long time since I did anything with it. – jcoder Jun 21 '11 at 12:19
  • casting ptr to double is dangerous, Lua has "user data" - post few centimeters above – Jacek Cz Apr 12 '16 at 05:32
0

You get the error because the functions are compiled twice (each time the header is included), and so the linker, which combines all the object files into the final executable, sees multiple definitions of the functions.

Like Armen wrote, one solution is to make the functions inline. This way the code for the functions is always copied whenever they are used. This is a feasible solution here because the functions are so small that the code won't get very bloated. If you have any larger functions in a header file or you need to organize your code better, you should take the code from the header file and put in in a cpp file (like in sehe's answer).

Antti
  • 11,944
  • 2
  • 24
  • 29