tags:

views:

317

answers:

6

Hey guys! When I try to do the following in a header file

static const char FOOT[] = "Foot";
static const char FEET[] = FOOT;

I get a compiler error of error: initializer fails to determine size of FEET. I was wondering what the cause of this is, and if there is a way to rectify it. Thanks!

+2  A: 

The cause is that you are saying that FEET[] is an array of chars but you're initializing it to a ptr; To rectify, you can change FEET from FEET[] to *FEET Could also do the same with FOOT

RobertL
Thanks for the explanation
spbots
+1  A: 

One way would be this

static const char FOOT[] = "Foot";
static const char *FEET = FOOT;
wallyk
+2  A: 

There is no '=' operator for arrays in C++, you need to use strcpy or something similar (which you can't do with a static const). Depending on your requirements the following might be useful:

#define contentsOfFoot "FOOT"
static const char FOOT[5] = contentsOfFoot;
static const char FEET[5] = contentsOfFoot;
static const char *feeet = FOOT;
Patrick
The original code does not use `=` operator. The original code performs initialization. `=` in initialization is not a `=` operator.
AndreyT
+4  A: 

Even though why you get this error has been answered, there's more to the story. If you really need for FEET to be an array, then you can make it a reference instead of a pointer:

char const foot[] = "foot";

char const (&feet)[sizeof foot] = foot;
// reference to array (length 5) of constant char
// (read the declarations "from the inside-out")

char const* const smelly_feet = foot;
// constant pointer to const char

int main() {
  cout << sizeof feet << ' ' << feet << '\n';
  cout << sizeof smelly_feet << ' ' << smelly_feet << '\n';
  cout << sizeof(void*) << " - compare to the above size\n";
  return 0;
}

(More examples of the inside-out rule.)

Secondly, static at file and namespace scope means internal linkage; so when you use it in a header, you'll get duplicate objects in every TU using that header. There are cases when you want this, but I see no reason for it in your code, and it's a common error.

Regarding array size: The sizeof operator returns the memory-size of an object or instance of a type. For arrays this means the total memory-size of all of its items. Since C++ guarantees that sizeof(char) is 1, the memory-size of a char array is the same as its length. For other array types, you can divide by the memory-size of one item to get the length of an array:

void f() {
  int array[5];
  assert((sizeof array / sizeof *array) == 5);
}

And you can generalize it to a function template:

template<class T, int N>
int len(T (&)[N]) {
  return N;
}
// use std::size_t instead of int if you prefer

This exists in boost as boost::size.

You may see code that uses sizeof array / sizeof *array, either through a macro or directly, either because it's old or doesn't want to complicate matters.

Roger Pate
+1 because it's closest to the declared requirements, and because references/pointers-to-arrays are little known and understood and it needs fixing :) however, I'd also use `sizeof` rather than hardcoding size in declaration of `feet`.
Pavel Minaev
Good suggestion, fixed.
Roger Pate
This was an excellent answer, thanks for all the info; have to learn something new every day!
spbots
+2  A: 

static is deprecated, and const variables at namespace scope are effectively static, anyway. Also, please reserve ALL_CAPS for preprocessor identifiers.

A bigger question is why you are using raw arrays at all. You very likely want something more like this:

std::string const foot = "foot";
std::string const feet = foot;

Or, more likely:

#include <string>

namespace spbots {

    typedef std::string string_t;

    string_t const foot = "foot";
    string_t const feet = foot;
}
Jeff Schwab
A: 

I want to emphasise that you shouldn't put that stuff in a header file. Variables should only be put in header files if you want to make them globally visible (generally not a great idea but it's a legitimate technique).

feet.h
extern char feet[];

feet.cpp
char feet[] = "FEET";

Now when you include feet.h in a different .cpp file, say leg.cpp, the declaration in feet.h means leg.cpp can see and use the array defined in feet.cpp

The extern keyword has the opposite meaning to the static keyword you use. A typical use of static is as follows;

feet.cpp
static char feet[] = "FEET";

Now feet[] is explicitly not visible outside feet.cpp. The static keyword is responsible for this lack of visibility. So static=local, extern=global and (perhaps unfortunately?) extern is the default, so if you don't use either keyword you get extern whether you like it or not.

Because static=local, there's nothing to communicate to other modules, so no need to have a declaration in a header file for other modules to see. Everything is kept within feet.cpp, probably a better idea than a global variable.

Another point I am implicitly trying to get through with this explanation is that declarations go into header files, definitions go into .cpp files. In your question you have a definition in a header file. Not illegal, but if you include it in more than one file (and if you don't, why would you put it in a header?), you will get a single variable defined multiple times, which will give you a link error.

All of this is actually old school C rather than C++ in the modern sense of the word. In other words you are really writing C, but since C is (almost) a subset of C++, you can still use C++ to do this stuff.

Bill Forster