How would I go about doing something like this?
header.h
struct myStruct;
extern myStruct array[];
main.cpp
#include "header.h"
struct myStruct{
int a = 0;
};
myStruct array[5];
array[0].a = 1;
file2.cpp
#include "header.h"
std::cout << array[0].a;
The size and layout of myStruct needs to be known everythere you try to access its contents, so you must either define it inside of the .h file, or only access it using opaque pointers and dedicated functions.
Also, using C arrays in C++ is somewhat outdated. You should use STL containers instead, such as std::array<T, N> or std::vector<T>.
Well, first of all you should put struct declarations in the header files.
Second, you can't put assignments to arrays or std::cout statements just loose in files. I'm assuming you did this for short code and not because you didn't know it needed to be in a function, but I'm pointing it out just in case.
Third, struct declarations require a semicolon
What you would do is have a header file:
header.hpp:
#pragma once
struct MyStruct {
int a = 0;
};
extern MyStruct array[5];
The extern here means that the data is somewhere else. So let's make the somewhere else.
header.cpp:
#include "header.hpp"
MyStruct array[5];
main.cpp:
#include "header.hpp"
void someFunction() {
...
array[0].a = 1;
...
}
file2.cpp:
#include <iostream>
#include "header.hpp"
void someOtherFunction() {
...
std::cout << array[0].a;
...
}
How would I go about doing something like this?
You could go about doing something like what you did by doing something like what you did, except fixing the bugs in your attempt. Here is the list of bugs:
You failed to end the definition of myStruct with a semicolon.
.c suffix is conventionally for C source files while you're writing C++. Your compiler will likely be confused unless you provide some unconventional options to the compiler.
You use cout which you forgot to declare. Or did you intend to use std::cout? In that case you must include <iostream> in order to use it, and use the appropriate namespace.
In file2.c, you use the class myStruct in a way that depends on the definition of myStruct without providing that definition.
array[0].a = 1; and cout << array[0].a; are expression statements. Expression statements may not be in namespace scope, and must be within a block scope. In your program, those expression statements are in the namespace scope which makes the program ill-formed.
Related
I think I'm doing something stupid, but I don't quite know what. I'm trying to rewrite a fairly simple library I have that is reading in some variables from a text file and then shares them with some other source files for use elsewhere. When I wanted to pass a double I was doing this:
#if !defined(SharedVariables_h)
#define SharedVariables_h
#include <vector>
extern double coeff_A;
#endif
and then doing this in both the source file where it was defined and the other source files where I want to use it:
#include "SharedVariables.h"
to make coeff_A available in the new source file.
But then my model got more complicated and I was using more coefficients so I decided to store them in a structure and pass that structure using extern instead. I created a new header file for the structure (CParameters.h):
#pragma once
#if !defined(CParameters_h)
#define CParameters_h
typedef struct
{
int coeff_A;
int coeff_B;
double coeff_C;
double coeff_D;
} SGlobalParameterData;
#endif
and then defined the struct like this:
#if !defined(SharedVariables_h)
#define SharedVariables_h
#include "CParameters.h"
#include <vector>
extern SGlobalParameterData globalParameters;
#endif
In the first source file where I read in all the values from the data files and using the values I've replaced:
#include "SharedVariables.h"
double coeff_A;
...
with
#include "SharedVariables.h"
SGlobalParameterData globalParameters;
globalParameters = readProperties(prefsFile);
....
In the second source file which also needs to use some of these variables I've added #include "SharedVariables.h" and then the IDE and compiler let me easily access globalParameters.coeff_A, globalParameters.coeff_B, etc.
I thought this should work and everything compiles without any errors, but it's not actually passing the values read into globalParameters to the second source file. Everything is just zero when I'm debugging the code.
So there are really two questions: 1) Is it possible to share structs using extern like for double, and 2) if it is, what have I done wrong.
Hopefully someone can point out my mistake.
Edit
I've added in an line of code in my example to show the function that assigns the values to the struct. This is working and the values read from the prefsFile are available and correct in the f1rst source file, but these values are not passed to source file 2. I'm going to do some more testing because it appears I may have made some other mistake elsewhere.
Your confusion stems from the use of typedef and mixing of declarations and definitions.
In C++ typedef isn't needed to define a struct type and is only confusing.
typedef struct { ... } SGlobalParameterData; - this declares a type SGlobalParameterData that is a struct. It defines no instance of the struct.
struct SGlobalParameterData { ... }; - same thing, declares a type SGlobalParameterData that is a struct.
struct { ... } globalParameterData; - this defines an object globalParameterData of an unnamed struct type.
struct SGlobalParameterData { ... } globalParameters; - this defines an object globalParameters of an struct type called SGlobalParameterData.
So... the following might be most readable/clean IMHO:
In the header:
struct SGlobalParameterData // type declaration
{
int coeff_A;
int coeff_B;
double coeff_C;
double coeff_D;
};
extern SGlobalParameterData globalParameters; // global instance *declaration*
In one of source files:
#include "the header above"
SGlobalParameterData globalParameters; // global instance *definition*
In other source files:
#include "the header above"
// globalParameters is already visible and usable
Of course you have to compile all source files and link them together into an executable.
Is it possible to share structs using extern like for double
Yes.
if it is, what have I done wrong.
Something that you haven't shown to us.
Everything is just zero
This is to be expected because variables with static storage are zero-initialised, and you never modify globalParameters in the example.
Here is your code running. Only change I made was to add some output, and actually set some other value than zero. That non-zero value works as expected: https://wandbox.org/permlink/CasO8c68W3FmBsQH
Suppose I have main.cpp and functions.cpp, a struct type named myStruct was declared in main.cpp.
Now, I need to process an array of myStruct in main.cpp using a function in functions.cpp.
Sample Code:
// main.cpp
#include "functions.cpp"
struct myStruct {
int x;
}
myStruct structArray[5];
int main()
{
...(some code)...
process(structArray);
}
// functions.cpp
void process(struct myStruct array[])
{
...(some code)...
}
After doing some searching, I found the most common solution is to use a global header file, in which declare myStruct, and then include the header file in both main.cpp and functions.cpp.
Unfortunately, I am required to use only two files to complete such a program, which means I couldn't add a separate header.h, making me confused.
Can anyone give me some suggestions on an alternative of a global header in this situation? Thanks.
I think you can do that using only two .cpp files
My idea is to have declaration of struct myStruct in both main.cpp and fucntion.cpp and to have process function declaration in main.cpp. like this..
// main.cpp
struct myStruct {
int x;
};
void process(struct myStruct array[]);
myStruct structArray[5];
int main()
{
...(some code)...
process(structArray);
}
and
// functions.cpp
struct myStruct {
int x;
};
void process(struct myStruct array[])
{
...(some code)...
}
And compile each separately and link together at linking time.
#include is like copying and pasting contents of the file. So if you define a struct in functions.cpp and include this file in main.cpp, you can access internals of this struct there.
Note however, that by convention you SHOULD NOT include .cpp (or other sources) files. In this case I would rather rename functions.cpp to functions.h and declare function there, if you really need to do it using only two files.
If you really really really can not move defintion of the struct from main.cpp to functions.* for whatever reason you could also include functions.* in main.cpp after the defintion of the struct, but this is a very ugly solution. If you work with strange requirements it would be a solution tough I would do everything else to avoid that.
So, I am working on a project and decided to split the code into multiple files as it was getting too big. However, a got a compilation error. I managed to recreate the error in this simple case:
//main.cpp
#include<iostream>
#include "classa.h"
using namespace std;
int main()
{
return 0;
}
The main does nothing it just includes classa.h
//classa.h
#ifndef CLASSA_H_INCLUDED
#define CLASSA_H_INCLUDED
#include<vector>
using namespace std;
vector<int> primes= {1,2,3,5,7,11,13,17,19};
class classa
{
private:
int a;
public:
int getA();
void setA(int newA);
};
#endif //CLASSA_H_INCLUDED
The class isn't even necessary for the error to occur. However, I wanted to have something in classa.cpp
//classa.cpp
#include "classa.h"
using namespace std;
int classa::getA()
{
return a;
}
void classa::setA(int newA)
{
a=newA;
}
It gives me the following error:
obj\Debug\sources\main.o:main.cpp:(.bss+0x0): multiple definition of `primes'
obj\Debug\sources\classa.o:classa.cpp:(.bss+0x0): first defined here
The problem is that unlike here in my project I cannot use some sort of constant or a define for the global variables as they are things that can be modified by different classes.
Make primes an extern variable, and declare it in your classa.h header, but only defined it once in classa.cpp.
Currently, as your compiler told you, primes exists twice, in main.cpp and in classa.cpp. Keep in mind, #include is merely text substitution.
classa.h:
extern std::vector<int> const primes;
classa.cpp:
std::vector<int> const primes = {1,2,3,5,7,11,13,17,19};
Read more about storage class specifiers here.
If you have .cpp file in overall - then it makes sense to split into
Into .h file:
extern std::vector<int> primes;
Into .cpp file:
using namespace std;
vector<int> const primes = {1,2,3,5,7,11,13,17,19};
"using namespace std" might cause conflicts between 3rd party libraries, but this occurs very rarely - I prefer to use "using namespace std" whenever possible. But if there are conflicts - then you might want to localized "using namespace std" into your own .cpp file. (Where you control what #include's that file has).
But sometimes you might not have .cpp file at all (e.g. only local inline functions or template classes) - then you can initialize vector like this:
__declspec(selectany) std::vector<int> primes = {1,2,3,5,7,11,13,17,19};
This will instruct linker to pick up only one copy (some of them), and discard everything else. This does not play well if you want to #ifdef some of initialization, but this is not normal use case anyway.
I prefer not to use const ever, because it's always pain in neck to get const right after 2-3 level conversions. I write in function comments what is input / what is output and what should not be modified. (Because that one can change over iterations)
I'm trying to wrap a C library in C++, to make it a modern, high level and idiomatic C++ library. What I want to do, is to make the C objects completely opaque and/or directly unavailable from the C++ code and wrap/replace them with higher-level alternatives.
The problem I'm facing with is simple: I want to include the C header only to the C++ source, so that the C++ header when included won't include the C header's declarations as well, that is, it won't pollute the global namespace.
But it looks like the correct separation of the header and source files does not allow me to do that. Here is a very much dummified version of my problem, the comments will tell you the rest:
my_header.h:
typedef enum
{
my_Consts_ALPHA = /* some special value */,
my_Consts_BETA = /* other special value */,
} my_Consts;
typedef struct
{
// members...
} my_Type;
void
my_Type_method(my_Type *const,
my_Enum);
my_header.hpp:
namespace my
{
enum class Consts; // <-- This header is missing the constant values of
// this enum, because its values are defined by
// the C header :(
class Type : public my_Type // <-- The super struct is coming from the
// C header, but I don't want to include
// that header here :(
{
public:
void
method(Consts constant);
};
}
my_source.cpp:
extern "C"
{
#include "my_header.h"
}
#include "my_header.hpp"
namespace my
{
enum class Consts
{
ALPHA = my_Consts_ALPHA,
BETA = my_Consts_BETA,
};
void
Type::method(Consts constant)
{
my_Type_method(static_cast<my_Type *const>(this),
static_cast<my_Consts>(constant));
}
}
So my questions are: am I missing something very obvious here? Is this even possible to achieve? Is there a trick that I'm not aware of?
In the comments of the question #AnalPhabet suggested sarcastically, that one should use #include of a C header inside a namespace. #n.m. confirmed, that it is actually a working solution, and now I tested it on my own setup, and fortunately it is working pretty fine.
(Although I have no idea, if this is implementation specific or not, but I tested on both g++ and clang++ and it is working.)
It does not solve the opaqueness problem, but at least it makes a bit harder to access to the raw C data directly as it is living in a separate namespace now, therefore the user can't accidentaly access, but willingly.
So, the my_header.hpp should look like this:
namespace my
{
extern "C"
{
#include "my_header.h"
}
enum class Consts
{
ALPHA = my_Consts_ALPHA,
BETA = my_Consts_BETA,
};
class Type : public my_Type
{
public:
void
method(Consts constant);
};
}
So wherever my_header.hpp is #include'd, the user can only access to the C values as follows:
my::my_Consts_ALPHA // The wrapped value is => my::Consts::ALPHA
my::my_Type // The wrapped value is => my::Type
my::my_Type_method(t,..) // The wrapped value is => t.method(..)
If the whole idea of writing high-level and idiomatic C++ wrapper is to bring safety, automatic memory management and convenient C++ types like std::sting, I would include C header into cpp file only.
Provide clean idiomatic C++ interface, and use C library only in the implementation.
Do not afraid to write a couple of utility functions that convert C data to C++ and back. If a C++ class should hold C-specific data, and it is not possible to replace it with C++ analog, use some type erasure technique to keep clean interface.
I wouldn't worry about performance due to such wrapping until I see it on top in a profiler log. In most cases it is not a bottleneck.
Again, splitting interface and implementation is usually a win.
UPDATE
Initially, I was thinking more about project specific C++ interface rather than universal C++ wrapper around C library.
Solution with extern "C" wrapped into a namespace looks correct to me (see ยง7.5 of C++11 standard). But, I've never seen this technique in the wild.
You can go further and add nested detail namespace to not pollute my namespace with C types. This trick is popular in header only libraries:
namespace my
{
namespace detail
{
extern "C"
{
#include "my_header.h"
}
}
enum class Consts
{
ALPHA = detail::my_Consts_ALPHA,
BETA = detail::my_Consts_BETA,
};
class Type : public detail::my_Type
{
public:
void
method(Consts constant);
};
}
Take into account that you can't make C functions completely opaque or wrap them to a single namespace when you link with static library. They have external linkage and know nothing about namespaces.
namespace A {
extern "C" void my_Type_method(my_Type *const, my_Enum);
}
namespace B {
extern "C" void my_Type_method(my_Type *const, my_Enum);
}
extern "C" void my_Type_method(my_Type *const, my_Enum);
Basically, all these declarations refer to the same C function. As C doesn't support namespaces and overloading, linker usually uses function names as unique identifiers (even argument types are ignored).
Anyway, this approach will help to avoid accidental access to C interface.
I'm not sure if it's language legal, but I think extern "C" is just there to unmangle functions, so as long as you keep them in the .cpp file you can get away with this.
This is a little profane, but it seems to work with gcc 4.3.5. It demonstrates that you can use C functions while also hiding them in a namespace.
I didn't bother with inheriting struct_t, but it should probably work. I have no idea if you can pull off the enum class.
foo.h
#ifndef foo_H
#define foo_H
typedef enum {
ALPHA,
BETA
} enum_t;
typedef struct
{
int i;
} struct_t;
void printit(struct_t print_me);
#endif // foo_H
foo.c
#include <stdio.h>
#include "foo.h"
void printit (struct_t print_me)
{
printf ("Hello World %d!\n", print_me.i);
}
bar.hpp
#ifndef bar_HPP
#define bar_HPP
namespace _foo {
// Don't need extern "C" since we're not using functions
#include "foo.h"
}
struct based_on_struct_t // : public _foo:struct_t // Do you really have to derive? It might be possible, but it's ugly
{
_foo::struct_t i;
double j;
based_on_struct_t (int _i, double _j) : j(_j) { i.i = _i; }
void print(void); // Gonna call printit, MUST be in .cpp
};
#endif // bar_HPP
bar.cpp
namespace _foo{
extern "C" {
#include "foo.h"
}
}
#include "bar.hpp"
#include <stdio.h>
void based_on_struct_t::print (void) {
// Call the old version...
printit(i);
// And do new crap
printf ("Goodbye World %d %f\n", i.i, j);
}
driver.cpp
#include "bar.hpp"
int main (void) {
based_on_struct_t B(10, .1);
B.print();
return 0;
}
Demo...
$ gcc foo.c -c -O3
$ g++ foo.o bar.cpp driver.cpp
$ ./a.out
Hello World 10!
Goodbye World 10 0.100000
$
I have a project using cocos2d-x library that contains a lot of classes. I have a .h file contains a global vector. I want to initialize it when the program starts in an intro page class. Intro page class has a graphical surface and a loader. Then I want to use that vector in my main class. The global vector's code is like bellow:
//globals.h
#ifndef _GLOBAL_H
#define _GLOBAL_H
#include <vector>
vector<int> a;
#endif
I am using push_back in intro page class. I have used extern and static keywords. my program makes a runtime linker error and it say your vector have been declared in appDelegate class (base class of cocos2d). when I put a static keyword behind it, it don't give me that linker error but it don't work correctly.
how can I correct this error? if you have another idea instead of this one, please share it. thank you.
You should have a design like the following:
shared.cpp
vector<int> a;
shared.h
extern vector<int> a;
somewhere.cpp
#include "shared.h"
void code() {
a.push_back(10);
}
Mind that, since you are using C++, you can uses classes as namespaces to avoid cluttering the global namespace, eg:
shared.cpp
vector<int> Common::a;
shared.h
class Common {
public:
static vector<int> a;
}
somewhere.cpp
#include "shared.h"
void code() {
Common::a.push_back(10);
}
You may have multiple declarations of an object, but you should only have one definition. To accomplish this, use extern to mark the declarations and the lack of extern to mark the definition.
In your header file, do this:
extern std::vector<int> a;
In exactly one of your source code files, do this:
std::vector<int> a;