1

I have two files, print_permu.c and gen_permu.cpp. I wish to compile print_permu.c file into an object file and then use the object file to compile gen_permu.cpp, which contains a call to a function in print_permu.c.

print_permu.c

#include<stdlib.h>
#include<stdio.h>

typedef char byte;

char *printable=NULL;
size_t pos,size,*char_cnt;

void __print_permu_recurse()
{
        if( pos==size )
        {
                printf("%s\n",printable);
                return;
        }
        byte iter = 25;
        while( iter>=0 )
        {
                if( char_cnt[iter] )
                {
                        printable[pos] = 'a'+iter;
                        --char_cnt[iter];
                        ++pos;
                        __print_permu_recurse();
                        --pos;
                        ++char_cnt[iter];
                }
                --iter;
        }
}

void print_permu(size_t *char_count)
{
        char_cnt = char_count;
        for(pos = 0,size = 0 ; pos<26 ; ++pos)
                size += char_count[pos];

        printable = (char*)malloc(sizeof(char)*(size+1));
        printable[size] = '\0';
        pos = 0;

        __print_permu_recurse();

        free(printable);
}

gen_permu.cpp

#include<iostream>
#include<string>

extern "C"
{
        #include"print_permu.c"
}

using namespace std;

int main()
{
        string str;
        size_t char_count[26]={},N,iter;

        cout << "string:"; cin >> str;
        N = str.size();

        for(iter=0;iter<N;++iter)
        {
                ++char_count[str[iter]-'a'];
        }

        print_permu(char_count);

        return 0;
}

I tried the following commands to compile the code in the said way.

$ gcc -c print_permu.c 
$ g++ print_permu.o gen_permu.cpp 
/tmp/ccQxAEea.o:(.bss+0x0): multiple definition of `printable'
print_permu.o:(.bss+0x0): first defined here
/tmp/ccQxAEea.o: In function `__print_permu_recurse':
gen_permu.cpp:(.text+0x0): multiple definition of `__print_permu_recurse'
print_permu.o:print_permu.c:(.text+0x0): first defined here
/tmp/ccQxAEea.o: In function `print_permu':
gen_permu.cpp:(.text+0xe0): multiple definition of `print_permu'
print_permu.o:print_permu.c:(.text+0xe9): first defined here
collect2: error: ld returned 1 exit status

$ g++ -c print_permu.c 
$ g++ print_permu.o gen_permu.cpp 
/tmp/ccPJA0kU.o:(.bss+0x0): multiple definition of `printable'
print_permu.o:(.bss+0x0): first defined here
/tmp/ccPJA0kU.o:(.bss+0x8): multiple definition of `pos'
print_permu.o:(.bss+0x8): first defined here
/tmp/ccPJA0kU.o:(.bss+0x10): multiple definition of `size'
print_permu.o:(.bss+0x10): first defined here
/tmp/ccPJA0kU.o:(.bss+0x18): multiple definition of `char_cnt'
print_permu.o:(.bss+0x18): first defined here
collect2: error: ld returned 1 exit status

First, I compiled code using gcc, hoping the object file would be compatible when compiling with g++. That didn't work. So, I tried to compile both the files using g++ alone, but to no avail.

How can I compile this code ? 'Am I missing any -options ?

Using gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04), Ubuntu 14.04, x86_64


Additionally,

I had initially wanted to declare the __print_permu_recurse function inside print_permu, which would be allowed in gcc (although not by C Standard). I had followed a similar process. Since that didn't work out, 'changed the code to be compatible even with C++.

kesari
  • 536
  • 1
  • 6
  • 16
  • 3
    First of all, don't use names with double leading underscore, they are reserved in all scopes. Secondly, don't include the *source* file into another source file. Instead make a *header* file containing the function prototypes of the functions you want to call, and include that. – Some programmer dude Aug 18 '15 at 14:46
  • Never `#include` a `.c` file, because there is never a reason to do so. It is only good for creating linker errors. – Lundin Aug 18 '15 at 14:49
  • you need to create a .h file for the prototypes of the functions in the .c file. That .h should be checking for the cplusplus being defined, and if defined, then use the extern c {...} syntax within the .h file. #include that .h file in both the .c and the .cpp files – user3629249 Aug 19 '15 at 14:16

1 Answers1

6

Your problem is this construct in gen_permu.cpp:

extern "C"
{
        #include"print_permu.c"
}

You have a source file print_permu.c, and a source file gen_permu.cpp, which includes print_permu.c.

When you compile print_permu.c to object code, it contains everything from source file print_permu.c.

When you compile gen_permu.cpp to object code, it contains everything from source file gen_permu.cpp and source file print_permu.c.

When you try to link the two of them together, you get "multiple definition" errors, because everything from print_permu.c is also defined in gen_permu.cpp, and the linker balks at the decision which definition to use.


What you probably intended to do was to include the declarations from print_permu.c. This is not done by including the whole source file, but by writing a header file print_permu.h:

// This is a "header guard". It avoids problems if the
// header is included more than once in a translation unit.
// The token used (here: PRINT_PERMU_H) is up to you, but
// should be sufficiently unique. All uppercase is a common
// convention.
#ifndef PRINT_PERMU_H
#define PRINT_PERMU_H

// This makes a C++ compiler aware that function declarations
// refer to *C* code, not C++ code. (The two languages generate
// different linker symbols.) A C compiler will just ignore this
// (as it should, since it does not need any special handling).
#ifdef __cplusplus
extern "C" {
#endif

// This just *declares* the *existence* of the function.
// The compiler can use this information (in gen_permu.cpp)
// to create a call-to-placeholder. The linker will then
// turn that into a call-to-function when you link the two
// object files together.
void print_permu(size_t *char_count);

// End of the C++ compatibility construct.    
#ifdef __cplusplus
}
#endif

// End of the header guard.
#endif

Then, instead of the construct at the top, just write

#include "print_permu.h"

in your C++ file (or C file, it does not matter thanks to the #ifdef __cplusplus).


There are various other issues with your source that do not result in immediate failure, but will bring problems if they become coding habit:

Reserved identifiers.

Global variables.

Magic numbers.

No comments, and assuming ASCII.

I am pretty sure that your code does some fishy things with characters, assuming an ASCII-7 character set, and will fail if 1) text contains international characters like öéß, or 2) the system in question has non-consecutive encodings for characters (e.g. EBCDIC).

But I got bored trying to figure out what your code is actually intended to do, because there are zero comments in there. (Imagine I had posted that header example without the comments...) So I cannot give you hints on how to improve, just that you should.

I also see a for loop without braces ({}). ;-)

Community
  • 1
  • 1
DevSolar
  • 67,862
  • 21
  • 134
  • 209