35

When trying to print the first command line argument:

std::cout << argv[0] << std::endl;

clang-tidy gives the warning:

warning: 'do not use pointer arithmetic' from [cppcoreguidelines-pro-bounds-pointer-arithmetic]

Is there an alternative way to use the values of argv without using pointer arithmetic? Isn't accessing a char** by any sensible method going to have to use pointer arithmetic?

I appreciate there are some specialised functions to handle command line arguments, but they seem too heavyweight for simply printing one argument.

I am writing in c++, using the clang compiler and building with cmake.

Praveen Kumar
  • 483
  • 1
  • 5
  • 12
user7119460
  • 1,451
  • 10
  • 20
  • 4
    If you only need `argv[0]`, you can use `*argv`. But beyond that, nope. – Benjamin Lindley Aug 16 '17 at 16:14
  • Try using `&argv[0]`. I believe `cout` wants a pointer to a single character. – Thomas Matthews Aug 16 '17 at 16:34
  • Does it still complain if you make `argv` an array and not a pointer? `char * argv[]`? – spectras Aug 16 '17 at 16:34
  • @spectras `argv` is an argument of `main`. It is always a pointer. – eerorika Aug 16 '17 at 16:36
  • @user2079303> or always an array. – spectras Aug 16 '17 at 16:40
  • 1
    @spectras never an array. Function arguments cannot be arrays. – eerorika Aug 16 '17 at 16:40
  • @user2079303> are you just nitpicking on the meaning of the syntax? Or are you implying that `int main(int argc, char * argv[])` is not valid? Of course it's still a pointer, but declaring it with array syntax makes the intent explicit and might be enough to get a code analyzer to shut up. – spectras Aug 16 '17 at 16:48
  • 1
    @spectras it is valid syntax, but calling the argument an array is not correct. It is a pointer regardless of syntax used. Confusing this is a common beginner error, and even if you understand the difference, beginners who read your comment might not. – eerorika Aug 16 '17 at 16:52
  • 4
    It's just implementation core guidelines ran amok. A better implementation should recognize the special case of `main` and stop bothering you about pointer arithmetic in this case. – SergeyA Aug 16 '17 at 16:54
  • 1
    @SergeyA It seems pretty clear to me that the implementation matches the guideline. You're free to disagree with the guideline in this case, or even in general, but an implementation which claims to warn about violations of that guideline should actually warn about violations of that guideline. It's easy to suppress warnings you disagree with, even on a line-by-line basis. –  Aug 16 '17 at 17:01
  • 4
    @hvd Than guidelines should make an exception for `main`. It is a well-known interface which is **not** going to change, so why bother developers with this warning? – SergeyA Aug 16 '17 at 17:03
  • 4
    @SergeyA As I point out in my answer, it's possible to read the command-line arguments without changing the interface in a way that this guideline supports. But I do think it would be good if they at least address it. Whether that is by making an exception or by showing how to implement it without violating the guideline doesn't matter too much to me. –  Aug 16 '17 at 17:07
  • 1
    That code is just fine. Any tool that tells you to rewrite it is simply wrong. – Pete Becker Aug 16 '17 at 17:20

1 Answers1

25

From clang-tidy - cppcoreguidelines-pro-bounds-pointer-arithmetic:

Pointers should only refer to single objects, and pointer arithmetic is fragile and easy to get wrong. span<T> is a bounds-checked, safe type for accessing arrays of data.

So yes:

Is there an alternative way to use the values of argv without using pointer arithmetic? Isn't accessing a char** by any sensible method going to have to use pointer arithmetic?

You're entirely correct. However, the guideline is about hiding that pointer arithmetic, letting a helper class do bounds checks before performing the arithmetic. You can construct a span<char*> from argv and argc. E.g. in C++20 you would write:

auto args = std::span(argv, size_t(argc));

and then use args instead of argv.

Mikhail
  • 20,685
  • 7
  • 70
  • 146
  • 1
    The issue with `span`, however, is that it is bounds-checked. I hate bounds-checked containers. – SergeyA Aug 16 '17 at 16:57
  • 3
    @SergeyA That sounds like you fundamentally disagree with the guideline. Which is perfectly fair, and in that case, don't turn on that warning. –  Aug 16 '17 at 17:02
  • 5
    I am in agreement with the majority of them, but this particular rule I find badly thought. A branch on every access is not what I ever want in my code. – SergeyA Aug 16 '17 at 17:08
  • @SergeyA It's not a big deal, bounds check happens only when you use the [] operator. There is no bounds check when you use iterators and constructs that build upon them. Such as the ranged for loop or the functions from the and headers. I would use those whenever possible, and I would rather have a slower program than an undiscovered zero-day buffer overflow exploit that would allow a hacker to run arbitrary code. – Calmarius Dec 19 '20 at 20:02
  • 4
    There is no bounds checking for `std::span` in C++20. – Mikhail Feb 12 '21 at 10:48
  • 2
    "`constexpr reference operator[](size_type idx) const;` Returns a reference to the `idx`-th element of the sequence. The behavior is undefined if `idx` is out of range" – Caleth Feb 12 '21 at 10:58
  • @Mikhail Shouldn't it be `auto args = std::span(argv, argc)`? – Dan Nestor Aug 17 '21 at 11:54
  • 2
    `std::span` accepts size as a `size_t` (unsigned type), while `argc` is an `int` (signed type). Without an explicit cast, there would be a warning about implicit signed->unsigned conversion. – Mikhail Aug 23 '21 at 10:18
  • 2
    @Mikhail and with the c-style cast there should be a warning about that too – Code Abominator Aug 26 '21 at 06:14