Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Compilation error - Most likely embarassingly easy, but I can't find what's wrong. (http://www.velocityreviews.com/forums/t439701-compilation-error-most-likely-embarassingly-easy-but-i-cant-find-whats-wrong.html)

Sune 10-07-2005 05:38 AM

Compilation error - Most likely embarassingly easy, but I can't find what's wrong.
 
Hi,

previously I used Eclipse CDT for compiling my files just to get
started with C and leave C++ behind. Now it's time to get a little more
serious so I've moved my files to a new workplace and begun to use GNU
Autotools. I'm sorry to say I'm new to gcc as well :(

Now I get the most ridiculous compile error which I'm unable to solve.
Can someone, please, help me with this? gcc output together with the
files mentioned in the gcc error output follows below. It is about 50
lines all in all, so I'm sure someone out there can find what's wrong
pretty quickly.

Thanks in advance anyone!
Sune

**************** Here is the gcc output *************
[sune@localhost rsd2]$ make all
make all-recursive
make[1]: Entering directory `/home/sune/gnu-ws/rsd2'
Making all in collections
make[2]: Entering directory `/home/sune/gnu-ws/rsd2/collections'
gcc -g -O2 -o collections_test DynamicString.o test_main.o
test_main.o(.rodata+0x0): In function `t1':
/home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
of `DynamicString_SUCCESS'
DynamicString.o(.rodata+0x0):/home/sune/gnu-ws/rsd2/collections/DynamicString.c:10:
first defined here
test_main.o(.rodata+0x4): In function `t1':
/home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
of `DynamicString_ERROR'
DynamicString.o(.rodata+0x4):/home/sune/gnu-ws/rsd2/collections/DynamicString.c:10:
first defined here
collect2: ld returned 1 exit status
make[2]: *** [collections_test] Error 1
make[2]: Leaving directory `/home/sune/gnu-ws/rsd2/collections'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/sune/gnu-ws/rsd2'
make: *** [all] Error 2

**************** Here is the beginning of my DynamicString.c file
*************
#include <string.h>
#include <stdlib.h>
#include <assert.h>

#include "DynamicString.h"

static const int FILE_ID = 0;

inline void DynamicString_init( DynamicString* string_obj, int trace_id
)
{
string_obj->stack_string[0] = '\0';
string_obj->heap_string = 0;
string_obj->string = 0;
string_obj->size = 0;
string_obj->capacity = DynamicString_stack_string_size;

}

**************** Here is the beginning of my DynamicString.h file
*************
#ifndef DYNAMICSTRING_H_
#define DYNAMICSTRING_H_

#include <stddef.h>

#include "../config.h" // Don't worry about the relative path, I'll
fix it...

const int DynamicString_ERROR=0;
const int DynamicString_SUCCESS=1;


enum { DynamicString_stack_string_size = 256 };

typedef struct DynamicString_
{
char stack_string[ DynamicString_stack_string_size ];
char* heap_string;
char* string;
size_t size;
size_t capacity;
} DynamicString;

**************** Here is the beginning of my test_main.c file
*************
#include <stdio.h>
#include <string.h>

#include "debug/Debug.h"
#include "collections/DynamicString.h"

int
t1(int),t2(int),t3(int),t4(int),t5(int),t6(int),t7 (int),t8(int),t9(int),t10(int);
int (*func[])(int) = { t1,t2,t3,t4,t5,t6,t7,t8,t9,t10 };

// Init
int t1( int trace_id )
{
DynamicString string;
DynamicString_init( &string, trace_id );
return 1; // Can't fail!
}


pete 10-07-2005 06:04 AM

Re: Compilation error - Most likely embarassingly easy, but I can't find what's wrong.
 
Sune wrote:

> Debug.h


What's that?

> int
> t1(int),t2(int),t3(int),t4(int),t5(int),
> t6(int),t7(int),t8(int),t9(int),t10(int);


What's that supposed to be?
It looks like an attempt at plural prototypes (no such thing).

--
pete

Keith Thompson 10-07-2005 07:00 AM

Re: Compilation error - Most likely embarassingly easy, but I can'tfind what's wrong.
 
pete <pfiland@mindspring.com> writes:
> Sune wrote:

[...]
>> int
>> t1(int),t2(int),t3(int),t4(int),t5(int),
>> t6(int),t7(int),t8(int),t9(int),t10(int);

>
> What's that supposed to be?
> It looks like an attempt at plural prototypes (no such thing).


Actually, I think it's legal.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.

Sune 10-07-2005 07:34 AM

Re: Compilation error - Most likely embarassingly easy, but I can't find what's wrong.
 
Hi,

yes, it's legal. Maybe it looks strange because of the odd linefeeds
added by Google.

BRs
/Sune


Martin Ambuhl 10-07-2005 08:23 AM

Re: Compilation error - Most likely embarassingly easy, but I can'tfind what's wrong.
 
Sune wrote:
> test_main.o(.rodata+0x0): In function `t1':
> /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
> of `DynamicString_SUCCESS'


This is the kind of error one gets from defining objects in header files.


> **************** Here is the beginning of my DynamicString.h file
> *************
> #ifndef DYNAMICSTRING_H_
> #define DYNAMICSTRING_H_
>
> #include <stddef.h>
>
> #include "../config.h" // Don't worry about the relative path, I'll
> fix it...
>
> const int DynamicString_ERROR=0;
> const int DynamicString_SUCCESS=1;


If you must have these in your header, you could
#define DynamicString_ERROR 0
#define DynamicString_SUCCESS 1

Or, if you have an allergy to #defines (get over it), you might try
enum {DynamicString_ERROR, DynamicString_SUCCESS};

Or, if you positively insist on defining objects in your header,
contrary to all common sense, add the 'static' qualifier.
static const int DynamicString_ERROR=0;
static const int DynamicString_SUCCESS=1;

Sune 10-07-2005 08:47 AM

Re: Compilation error - Most likely embarassingly easy, but I can't find what's wrong.
 
Hi,

thanks, that was the problem.

I want to have them (DynamicString_ERROR and DynamicString_SUCCESS) in
my header accessible to clients so that clients of DynamicString can
use them to test the outcome of a call to functions I didn't include in
the code I pasted into my post.

What would be a more proper way of doing this? (Just beginning to get
into C you know)

Thanks again
/Sune


Niklas Norrthon 10-07-2005 08:50 AM

Re: Compilation error - Most likely embarassingly easy, but I can't find what's wrong.
 
"Sune" <sune_ahlgren@hotmail.com> writes:

> Hi,
>
> Now I get the most ridiculous compile error which I'm unable to solve.
> Can someone, please, help me with this? gcc output together with the
> files mentioned in the gcc error output follows below. It is about 50
> lines all in all, so I'm sure someone out there can find what's wrong
> pretty quickly.


> test_main.o(.rodata+0x0): In function `t1':
> /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
> of `DynamicString_SUCCESS'


This means that the varible DynamicString_SUCCESS is *defined* in
multiple places. The problem is that you *define* it in a header
file that gets included in several translation units. The fix is
to *declare* the varible in the header file, and then *define* it
in only one translation unit.

*Declare* means telling the complier that there exist a name
'DynamicString_SUCCESS', which is *defined* somewhere else. If the
definition is in some other translation unit, the compiler will
let the linker resolv it.

*Define* means *declare* and in addition restore some storage for
the name.

/* Examples (assume file scope) */
extern int foo1; /* Declaration only */
int foo2; /* Declaration and definition */
int foo3 = 42; /* Declaration and definition */

extern void foo4(void); /* Declaration only */
void foo5(void); /* Declaration only */
void foo6(void) { } /* Declaration and definition */


pete 10-07-2005 12:23 PM

Re: Compilation error - Most likely embarassingly easy, but I can'tfind what's wrong.
 
Keith Thompson wrote:
>
> pete <pfiland@mindspring.com> writes:
> > Sune wrote:

> [...]
> >> int
> >> t1(int),t2(int),t3(int),t4(int),t5(int),
> >> t6(int),t7(int),t8(int),t9(int),t10(int);

> >
> > What's that supposed to be?
> > It looks like an attempt at plural prototypes (no such thing).

>
> Actually, I think it's legal.


That's a new one on me.
Thank you.

--
pete

tanmoy87544@gmail.com 10-07-2005 12:49 PM

Re: Compilation error - Most likely embarassingly easy, but I can't find what's wrong.
 

Sune wrote:
> test_main.o(.rodata+0x0): In function `t1':
> /home/sune/gnu-ws/rsd2/collections/test_main.c:12: multiple definition
> of `DynamicString_SUCCESS'
> DynamicString.o(.rodata+0x0):/home/sune/gnu-ws/rsd2/collections/DynamicString.c:10:
> first defined here


What this is saying is that it has found two objects, one in the
compilation unit it calls DynamicString.o, and one in test_main.o which
have the same name DynamicString_SUCCESS, and both visible externally!
So, it is confused ... (similar error with DynamicString_Error later).

> **************** Here is the beginning of my DynamicString.h file
> *************
> #ifndef DYNAMICSTRING_H_
> #define DYNAMICSTRING_H_


Okay this ensures that the contents are not included twice in any one
compilation unit. That is irrelevant when compiling separate
compilation units (gcc interprets each top level .c file, i.e. the ones
on the command line, as a separate compilation unit).

> const int DynamicString_ERROR=0;
> const int DynamicString_SUCCESS=1;


Now, these are declaring two variables DynamicString_ERROR and
DynamicString_SUCCESS outside any functions (assuming the .h file is
included outside any functions as you showed in the portion I deleted).
Such declarations, by default, declare entities with external linkage:
i.e. specify that all such entities (i.e. all entities with external
linkage everywhere in the program, not only in the compilation unit)
with the same name should refer to the same entity. So, they have the
same type, address etc., and changing the value of any of them (if they
can be changed) should change all with the same name. The compiler is
not required to check that you do not violate this, but as you saw, it
certainly can.

However, they have been initialized: this changes them from mere
declarations into definitions! Which means, you are instructing the
compiler to actual create such objects in the compilation unit.

So, now, when you include this in multiple compilation units, what is
the compiler supposed to do? The external linkage is forcing the
interpretation that there should only be one entity with each name,
whereas the definition is forcing one object per compilation unit in
which the inclusion takes place.

So, what options do you have other than having only one compilation
unit? Well, here are a few:

a) Use #define instead of an object. This just defines a new
preprocessor token which behaves identically to the number in the
compilation stage. So, it is not scoped (well, you are at global
scope, so that is not terribly important, except you cannot hide it by
local definitions), has no name space (so you cannot use it as a label
or tag etc.), and since you don't create an object, you cannot take its
address. You however get a constant expression which can be used in
places where an object evaluation is not allowed.

b) Not initialize the variable and declare it as an extern (If you do
not put the extern, initialization to 0 is assumed if no other
declaration in the same compilation unit defines it). In this case,
you can make sure it gets declared in exactly one compilation unit
somehow. In that case, no other compilation unit knows what value the
object has, possibly loosing optimization opportunities, but otherwise
behaves identically.

c) Declare it as static. This gives it `internal' linkage: that is it
is the same as every other entity with the same name and internal
linkage in the compilation unit, but distinct from every object or
function of the same name in other compilation units. This takes up
space in each compilation unit, but for such small amount of stuff,
that presumably does not matter. Two things to note: (1) an extern
declaration where a declaration with internal linkage is visible (i.e.
in scope and not hidden), provides a further declaration of the entity
with internal linkage (and thus refers to the same entity), and does
not declare it with external linkage. (2) If you do declare the same
name with both internal and external linkage in the same translation
unit, you get undefined behaviour.
(C++ and C differ subtly for const objects at global scope with neither
extern nor static specified: I am obviously giving the C rules here)

d) As you did below
>
>
> enum { DynamicString_stack_string_size = 256 };


This defines a new token (not a preprocessor token) which is still an
integral constant expression. Such identifiers, however, do not refer
to objects, and hence you cannot take their address, but are scoped and
obey name spaces.


Sune 10-07-2005 03:42 PM

Re: Compilation error - Most likely embarassingly easy, but I can't find what's wrong.
 
Hi,

thanks for a real good explanation. I have changed it into external
linking with 'extern' and it works fine. I prefer objects in order to
avoid magic numbers during debugging.

BRs
Sune



All times are GMT. The time now is 12:11 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.