Best pointers questions in September 2011

segfault : interview question/C puzzle

27 votes

I came across the following C puzzle:

Q: Why does the following program segfault on IA-64, but work fine on IA-32?

  int main()
  {
      int* p;
      p = (int*)malloc(sizeof(int));
      *p = 10;
      return 0;
  }

I know that the size of int on a 64 bit machine may not be the same as the size of a pointer (int could be 32 bits and pointer could be 64 bits). But I am not sure how this relates to the above program. Any ideas?

The cast to int* masks the fact that without the proper #include the return type of malloc is assumed to be int. IA-64 happens to have sizeof(int) < sizeof(int*) which makes this problem obvious.

The comp.lang.c FAQ has an entry discussing why casting the return from malloc is never needed and potentially bad.

Why can't a constant pointer be a constant expression?

19 votes

The following program compiles:

template <const int * P>
class Test{};

extern const int var = 42; //extern needed to force external linkage

int main()
{
    Test<&var> test;
}

This one, however, doesn't, which is a surprise for me:

template <const int * P>
class Test{};

extern const int var = 42; //extern needed to force external linkage
extern const int * const ptr = &var; //extern needed to force external linkage
int main()
{
    Test<ptr> test; //FAIL! Expected constant expression.
}

Alternative example:

int main()
{
   const int size = 42;
   int ok[*&size]; //OK

   const int * const pSize = &size;
   int fail[*pSize]; //FAIL
}

I have concluded that a pointer just can't be a constant expression regardless of whether it's const and initialized with a constant expression.

Questions:

  1. Is my conclusion true?
  2. If so, why can't a pointer be a constant expression? If not, why don't the above programs compile?
  3. Does C++0x(C++11, if you will) change anything?

Thanks for any insights!

It's a bit more complicated. In C++03 and C++11, &var is a constant expression if var is a local static / class static or namespace scope variable. This is called an address constant expression. Initializing a class static or namespace scope pointer variable with that constant expression is guaranteed to be done before any code is run (static initialization phase), because of it being a constant expression.

However only in C++11, a constexpr pointer variable that stores the address &var can also be used as an address constant expression and only in C++11, you can dereference an address constant expression (actually, you can dereference even more - even local array element addresses, but let's keep it ontopic) and if it refers to a constant integral variable initialized prior to the dereference or a constexpr variable, you again get a constant expression (depending on the type and value category, the kind of constant expression may vary). As such, the following is valid C++11:

int const x = 42;
constexpr int const *px = &x;

// both the value of "px" and the value of "*px" are prvalue constant expressions
int array[*px];
int main() { return sizeof(array); }

If so, why can't a pointer be a constant expression? If not, why don't the above programs compile?

This is a known limitation in the Standard's wording - it currently only allows other template parameters as arguments or & object, for a template parameter of pointer type. Even though the compiler should be capable of doing much more.