C++ in C

Discussion in 'Mac Programming' started by farmerdoug, Jan 17, 2012.

  1. macrumors 6502a

    Joined:
    Sep 16, 2008
    #1
    I have two programs- one written in C, one in C++. I need to imbed the C++ code into the C program.
    Can I do this? How?

    Thanks?
     
  2. macrumors 6502

    Joined:
    Mar 8, 2004
    #2
    http://stackoverflow.com/questions/199418/using-c-library-in-c-code

    http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.6

    The real important part is this:

    Code:
    
    extern "C" int C_Wrapper_Function(char *bar)
    {
        return Actual_C_Plus_Plus_Function(std::string(bar));
    }
    
    
    In your C++ code you have to create a C API. Usually when I do similar things on the PC side I compile my "alien" code into a DLL and link it into my program. It keeps me sane. That might not be necessary when mixing C & C++ however (usually I mix Standard C++, C++/CLI, WPF C#, and Silverlight C#, together depending on the project, which has its own set of complications).

    The Stack Overflow link has some info for manipulating your objects as well.
     
  3. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #3
    Lunch first, then I will try.
    Thanks. I may have to get back to you.
     
  4. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #4
    I'm off to a bad start. This in the header file
    extern "C" float * shift(float *five)
    {
    float array[9];
    return array;
    }

    produces ./include/pcxp.h:193: error: expected identifier or '(' before string constant
    make: *** [pcxp] Error 1

    Something stupid?

    ----------

    Ok. got around that.
     
  5. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #5
    prototype in code.c
    #ifdef __cplusplus
    extern "C" void shift(float *nine, float *twentyfive);
    #endif


    new routine in code.h

    #ifdef __cplusplus
    extern "C" void shift(float *nine, float *twentyfive)
    {
    #include "nr3.h"
    #include "interp_1d.h"
    #include "interp_linear.h"
    #include "interp_2d.h"
    #include "LUdcmp.h"
    #include "krig.h"


    int i;
    for (i = 0; i < 9; i++)
    nine = i;
    }
    #endif

    call in separate function

    int weightersum_cubeextract()
    {

    float *shiftedarray, *arraytobeshifted;

    shiftedarray = (float*)calloc(9, sizeof (float));
    arraytobeshifted = (float*)calloc(25, sizeof (float));

    shift(shiftedarray, arraytobeshifted);
    for (i= 0; i < 9; i++)
    printf("%f \n", shiftedarray);

    ...
    }

    Error

    pcxp.c: In function 'weightedsum_cubextract':
    pcxp.c:2882: warning: implicit declaration of function 'shift'
    Undefined symbols:
    "_shift", referenced from:
    _weightedsum_cubextract in ccmzV96Z.o
    ld: symbol(s) not found
    collect2: ld returned 1 exit status
    make: *** [pcxp] Error 1
     
  6. macrumors 6502

    Joined:
    Mar 8, 2004
    #6
    I'm getting the idea you're trying to compile the C++ cpp files from a C compiler right (that is to say, GCC without C++ support turned on)? You need to compile the C++ file as a library and link the library and program together.

    When I get home I'll try to do it on the Mac side of things (since its not the same as doing it in Visual Studio) so I can be more helpful.
     
  7. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #7
    thanks
    would really appreciate it.
    Here's the make file I am using.


    #Makefile for the Project 1640 data pipeline

    PIPELINEPATH = PIPELINEDIR=.
    DATAPATH = ROOTDATADIR=/DATA0/PHASE2DATA
    LIBRARYPATH = LIBRARYDIR=./LIBRARY

    CC = gcc -arch x86_64
    CFLAGS = -Wall -g -O1
    IDIR = ./include
    LIBS = -lm -lcfitsio -lgsl -lgslcblas -lmpfit -lfftw3

    EXECS = pcxp
    OBJS = pcxp.o

    pcxp: pcxp.c
    ${CC} ${CFLAGS} -I${IDIR} -D${PIPELINEPATH} -D${DATAPATH} -D${LIBRARYPATH} pcxp.c ${LIBS} -o pcxp
    # ${CC} ${CFLAGS} -I${IDIR} -DMEMWATCH -D${PIPELINEPATH} -D${DATAPATH} -D${LIBRARYPATH} pcxp.c memwatch.c ${LIBS} -o pcxp

    all: ${EXECS}

    clean:
    rm -f ${OBJS} ${EXECS}
     
  8. macrumors 6502

    Joined:
    Apr 24, 2008
    #8
    Farmerdoug, you have #ifdef'ed the entire implementation of the shift() function. Looking at your error code, it seems you're calling it in a C file, where __cplusplus will not be defined. Your compiler has never seen the implementation of shift() at all. The normal way of doing it is this:

    In shift.h:
    Code:
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    // your prototypes here, including shift:
    void shift(float *nine, float *twentyfive);
    
    #ifdef __cplusplus
    } // to balance the opening brace above
    #endif
    In shift.c:
    Code:
    #include "shift.h"
    
    void shift(float *nine, float *twentyfive)
    {
        // implementation of shift()
    }
    In MyProgram.cpp:
    Code:
    #include "shift.h"
    
    int main(void)
    {
        float nine[9];
        float twentyfive[25];
        shift(nine, twentyfive);
    
        return 0;
    }
     
  9. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #9
    Okay.
    So I did what you said without any C++ code. There were no problems.
    Then moved a copy of it to my include folder and I tried to include it.
    As probably know, it didn't work. How do I add all the include files that are required by iostream?
     
  10. jiminaus, Jan 17, 2012
    Last edited: Jan 17, 2012

    macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
  11. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #11
    my header file now has

    #include "iostream"
    #include "ios"
    #include "streambuf"
    #include "istream"
    #include "ostream"
    #include "__config"
    #inlcude "__locale"
    #include "iostream"

    lots of errors from the include files
    for example
    ./include/__config:259: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'std'
    ./include/__config:274: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
    ./include/__config:275: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
    ./include/__config:276: error: expected '=', ',', ';', 'asm' or '__attribute__' before '<' token
    In file included from ./include/ios:215,
    from ./include/iostream:38,
    from ./include/cppheader.h:9,
    from pcxp.c:12:
    ./include/iosfwd:94: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'std'
    In file included from ./include/ios:216,
    from ./include/iostream:38,
    from ./include/cppheader.h:9,
    from pcxp.c:12:
    ./include/__locale:15:18: error: string: No such file or directory

    ----------

    jiminaus

    I can't find this on the thread.
    When you compile the C file, use gcc. When you compile the C++ file, use g++ instead.

    Never-the-less, in the make file I have to first compile by C++ code with g++ then link the .o file to the C code with gcc?
     
  12. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #12
    Let's start with the basic principles:

    You have a C compiler, and a C++ compiler. The C compiler compiles .c files, and the C++ compiler compiles .cpp files. .c files cannot call C++ functions, but .cpp files can contain C functions, and the C functions inside a .cpp file _can_ call C++ functions.

    So if you want to call C++ code from a .c file, you need to write a write a C function that calls the C++ code inside a .cpp file. And you need a header file that can be read from .cpp and from .c files. So first the header file. If you just write for example

    Code:
    int f (int x);
    in a header file then this won't work: The C compiler thinks it is a C function named f, but the C++ compiler thinks it is a C++ function named f. And a C and C++ function are not the same. So instead you write in the .h file:

    Code:
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    int f (int x);
    
    #ifdef __cplusplus
    }
    #endif
    When the C compiler compiles it, the 'extern "C" {' and '}' are ignored. Just the declaration of the C function f is compiled. When the C++ compiler compiles it, the 'extern "C" {' and '}' are compiled, and they tell the C++ compiler "this is a C function named f", so now C and C++ agree.

    Now you implement the function f. You just add it to a .cpp file that includes the header file. Because f is declared as a C function, the C++ compiler will compile it as a C function, so C code can call it. But because it is compiled by the C++ compiler, and the C++ compiler knows how to call C++ code, the function f can call any C++ code.
     
  13. Mac_Max, Jan 17, 2012
    Last edited: Jan 17, 2012

    macrumors 6502

    Joined:
    Mar 8, 2004
    #13
    You'll have to correct me again if I'm misreading your posts, but I don't believe you can expose any function that uses IOStream or any of the other C++ STL headers in C, even when obfuscating them through a library with a C API. I think you need to write a wrapper that implements the same functionality using native C functions and use #ifdefs for C & C++ for conditional compilation. I could be wrong but I haven't seen anything in google that says otherwise.

    The biggest problem is that even if the gcc can find the libraries and figure out each and every type, it will have no idea how to deal with <<, >>, new, delete, references, some keywords, and a few other things I can't remember.

    Assuming you have XCode, I've attached three projects. One generates a static library, one is a C++ command line test, and the third is a C command line test. The command line apps do the same thing, just one in C++ and the other in C. They demonstrate the basic way to wrap a C++ class with a C API so you can use the class. I used this link for help when writing it:

    http://developers.sun.com/solaris/articles/mixing.html#iostream

    I'll paste the code of the C++ library and the C test code so everyone can see it without downloading:

    CPPClass.h:
    Code:
    #ifndef CPPLib_CPPClass_h
    #define CPPLib_CPPClass_h
    #ifdef __cplusplus
    
    class CPPClass{
        
    public:
        static void StatPlusPlus(int* aNum);
        void PlusPlus(int* aNum);
        
    };
    # else
    //This is very important!  Also seen as extern struct <identifier> <identifier> 
    struct CPPClass;
    
    #endif
    
    //C API
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
        /* ANSI C prototypes */
    #if defined(__STDC__) || defined(__cplusplus)
        extern void c_StatPlusPlus(int*);
        extern void c_PlusPlus(struct CPPClass*, int*);   
    
    #endif
        
    #ifdef __cplusplus
    }
    #endif
    
    //C and C++ friendly
    
    #ifdef __cplusplus
    extern "C" {
    #endif
        
    void GlobalPlusPlus(int* aNum);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    
    CPPClass.cpp:
    Code:
    //
    //  File.cpp
    //  CPPLib
    //
    //  Created by Max on 1/17/12.
    //  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
    //
    
    #include "CPPClass.h"
    
    void CPPClass::StatPlusPlus(int* aNum){
        (*aNum)++;
    }
    
    
    void CPPClass::PlusPlus(int* aNum){
        (*aNum)++;
    }
    
     /* ANSI C prototypes */
    
    void c_StatPlusPlus(int* Var)
    {
        CPPClass::StatPlusPlus(Var);
    }
    
    void c_PlusPlus(struct CPPClass* Target, int* Var)
    {
        Target->PlusPlus(Var);
    }
    
    void GlobalPlusPlus(int* aNum){
        (*aNum)++;
    }
    
    Inside the C test program I've included alongside main: libCPPLib.a (the output from the C++ static library XCode project) and the header CPPClass.h.

    main.c:
    Code:
    #include <stdio.h>
    #include "CPPClass.h"
    
    int main (int argc, const char * argv[])
    {
    
        //ported from my CPP Test
        int TestInt = 10;
        
        //Static
        c_StatPlusPlus(&TestInt);
        printf("%d \n", TestInt);
        
        //Class
        //Important! Must be a pointer to CPPClass
        //CPPClass is an incomplete specification and the C compiler won't know what to do with it.
        //Thankfully it always knows what to do with a pointer!
        struct CPPClass* CP;
        c_PlusPlus(CP, &TestInt);
        printf("%d \n", TestInt);
        
        //Global
        GlobalPlusPlus(&TestInt);
        printf("%d \n", TestInt);
        
        printf("Hello, World!\n");
        return 0;
    }
    
    Sorry for the length, if MR supported the
    tags I would have used them.
     

    Attached Files:

  14. macrumors 6502

    Joined:
    Mar 8, 2004
    #14
    Btw, is there any reason you have to use a C compiler? Could you just use a C++ compiler but write everything the same as you would in C? That would solve 100% of your issues.
     
  15. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #15
    Sorry, I haven't gotten back to you guys. I found a work around and been pursuing the main task ever since. Please don't think the effort was wasted. I did learn some new tricks.
     
  16. macrumors 6502

    Joined:
    Mar 8, 2004
    #16
    No worries, I got to teach myself how to use/include C/C++ libraries in XCode haha. Did you end up getting the libraries with STL references to work?
     
  17. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #17
    No even simpler. I remembered.
    In previous work, I started with a 2-d spline fit from an old copy of Numerical Recipes in C. It was written in C but then I switched to a different fit from a newer edition of the book. I switched because the new code could use uneven point spacing. It was written in C++.
    This time I needed a 2-d spline fit for someone else's existing C code and went straight to the C++ fit. After a day of trying to put them together, I remembered the old C code and because I was using even spacing I no longer had to worry about C++.
    Thanks again for your help.

    PS. I learned Tuesday that C++ was an invention from the evil Microsoft Empire. I wonder why Numerical Recipes in C switched to C++
     
  18. jiminaus, Jan 19, 2012
    Last edited: Jan 19, 2012

    macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #18
    Where did you learn that?! What bollox! Bjarne Stroustrup started developing C++ in 1979 at Bell Labs. In 1985, he published the first edition of The C++ Programming Language. Microsoft didn't release its first C++ compiler until 1992. AFAIK Bjarne Stroustrup has never worked for Microsoft.

    Managed C++ is a whole other story.
     
  19. Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #19
    You appear to be confusing C++ and C#. (C++ ++ ;) )

    B
     
  20. macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #20
    Apparently this is enough of a misconception that Bjarne Stroustrup put it on his FAQ.

     
  21. thread starter macrumors 6502a

    Joined:
    Sep 16, 2008
    #21
    I stand corrected. Never having found a use for OOP, anything I can blame on Bill Gates, I can. The time wasted dealing with windows and windows machines has left me with a permanent dislike for the man, the company and its products.
     
  22. macrumors 6502

    Joined:
    Apr 24, 2008
    #22
    Yes you can, as long as the function prototype doesn't contain any C++ types. For example, it's perfectly fine to have

    Code:
    double f(int i)
    {
        std::vector<double> values(some_cpp_function());
        return values[i];
    }
    don't mind the crappy code itself; I just wanted to point out that in the implementation of the function, you're free to use as much C++ as you like. You will still be able to call this function from C.

    ----------

    It's not like Bill Gates (or anyone else at Microsoft) invented OOP...
     
  23. macrumors 6502

    Joined:
    Mar 8, 2004
    #23


    Right I know about that. I thought the OP was trying to directly import headers from C++ and do something like:

    Code:
    
    void foo(std::string bar)
    {
            cppFoo(bar);
    }
    
    
    Before I knew where he stood on that issue, I thought he was trying to do something COM style but without all the "magic" that lets you use non-native but COM friendly types in any Windows codebase. Doesn't sound like he's much of a MS fan though haha.
     

Share This Page