12

Consider the following snippet:

#include <iostream>
using namespace std;

int a[10][2];
int b[10][2];

int main(){

  //intended
  cout << a[0][0] - b[0][0] << endl;

  //left out dimension by mistake
  cout << a[0] - b[0] << endl;

}

Obviously (or maybe not per comments) the second case is valid pointer arithmetic in both C and C++ but in the code base I am working with it is generally a semantic mistake; a dimension has usually been left out in a nested for loop. Is there any -W flag or static analysis tool that can detect this?

Deanie
  • 2,316
  • 2
  • 19
  • 35
frankc
  • 11,290
  • 4
  • 32
  • 49
  • 4
    If I'm not mistaken, only arithmetic between related pointers is defined behavior. The "pointers" `a[0]` and `b[0]` are not really related, so it's most definitely undefined behavior IMO. – Some programmer dude Dec 23 '13 at 22:50
  • You could rig up your compiler to print out the parse tree and check if any arithmetic expressions involve operands of pointer type. Clang might make this easy, no idea. – Kerrek SB Dec 23 '13 at 22:50
  • Ah, in light of Joachims astute observation, try Clang's UBSan. – Kerrek SB Dec 23 '13 at 22:51
  • @KerrekSB Well, I could be wrong (it's been known to happen!). I just have a recollection of reading it somewhere "official". :) – Some programmer dude Dec 23 '13 at 22:52
  • Interesting as I have only tried gcc so far with the enormous set of warning flags listed in http://stackoverflow.com/questions/399850/best-compiler-warning-level-for-c-c-compilers I'll give clang a shot. We don't normally use it here. – frankc Dec 23 '13 at 22:53
  • 1
    @JoachimPileborg: you are right. The relevant clause is 5.7 [expr.add] paragraph 6. – Dietmar Kühl Dec 23 '13 at 23:00
  • @frankc: You can use clang for the static analysis and the useful error messages, and GCC for the well-generated code :-) – Kerrek SB Dec 23 '13 at 23:00
  • Random though: use regular expressions to match `anything[number] operation anything[number]`? – Vittorio Romeo Dec 23 '13 at 23:35
  • I tried clang++ with -fsanitize=undefined, as well as -Wall -pedantic and there were no warnings on this test code. It's an older version of clang though in my repo (2.8) so i might need to try a newer one – frankc Dec 24 '13 at 15:22

3 Answers3

8

You could use std::array which will not allow that:

    using d1=std::array<int, 2>;
    using d2=std::array<d1, 10>;

    d2 a;
    d2 b;

    std::cout << a[0][0] - b[0][0] << endl;  // works as expected

    std::cout << a[0] - b[0] << endl;        // will not compile
Glenn Teitelbaum
  • 10,108
  • 3
  • 36
  • 80
  • I tried this and it fails to compile as expected. I would actually prefer something that has warnings on existing unchanged code, but so far nothing I have tried to do that so this is the best answer – frankc Dec 24 '13 at 15:49
4

Another option is to use a specialized multidimensional array library with appropriate operator error handling, such as boost::multi_array (http://www.boost.org/doc/libs/1_55_0/libs/multi_array/doc/user.html). This is usually a better idea then using nested containers or POD arrays.

oakad
  • 6,945
  • 1
  • 22
  • 31
2

If this is only concern for << operator as in example, overload of operator << for int* might help - you can overload operator to generate compile-time error.

Ilya Kobelevskiy
  • 5,245
  • 4
  • 24
  • 41
  • Unfortunately that was just a way for me to show this example in a small snippet. In reality, it's much more insiduious, littered along a bunch of if statements in a huge piece of scientific code. Good thought, though. – frankc Dec 23 '13 at 22:54