Search code examples
c++c++11implicit-conversionunsignedsigned

How to fix implicit conversion warnings?


I'm reading C++ How To Program 9th Edition, trying to learn c++, and attempting the exercise with the Knight's Problem in Chapter 7.

Based on the "64" in the output, the code clearly has some sort of logic error (which I will fix on my own), but before doing this, I'm stuck on understanding and what to do about the compiler warnings.

I've declared board as a two-dimensional array of unsigned int because it can only contain values 0-7. Likewise, I've declared variables in for loops as unsigned int, for the same reason.

I've read responses on stackoverflow about this but they quickly go over my head.

#include <iostream>
#include <array>
#include <iomanip>

using namespace std;

void printArray(const array< array< unsigned int, 8 >, 8 >);

int main() {
  array< array< unsigned int, 8 >, 8 > board = {};
  array< int, 8 > horizontal = {{ 2, 1, -1, -2, -2, -1, 1, 2 }};
  array< int, 8 > vertical = {{ -1, -2, -2, -1, 1, 2, 2, 1 }};
  unsigned int currentRow = 0;
  unsigned int currentCol = 0;
  for (unsigned int i = 0; i < 64; i++) {
    board[currentRow][currentCol] = i + 1;
    for (unsigned int j = 0; j < 8; j++) {
      if (currentRow + horizontal[j] >= 0 &&
        currentRow + horizontal[j] < 8 &&
        currentCol + vertical[j] >= 0 &&
        currentCol + vertical[j] < 8 &&
        board[currentRow + horizontal[j]][currentCol + vertical[j]] == 0
      ) {
        currentRow = currentRow + horizontal[j];
        currentCol = currentCol + vertical[j];
        break;
      }
    }
  }
  printArray(board);
}

void printArray(const array< array< unsigned int, 8 >, 8 > myBoard) {
  for ( unsigned int i = 0; i < 8; i++) {
    for ( unsigned int j = 0; j < 8; j++) {
      cout << '[' << setw(2) << setfill('0') << myBoard[i][j] << "] ";
    }
    cout << endl;
  }
}

Output:

~/Programming/cpp/knight => make
rm -fr build/*
clang++ -std=c++11 -stdlib=libc++ -Weverything -Wno-c++98-compat src/main.cpp -o build/main -Isrc/
src/main.cpp:18:24: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
      if (currentRow + horizontal[j] >= 0 &&
                     ~ ^~~~~~~~~~~~~
src/main.cpp:18:38: warning: comparison of unsigned expression >= 0 is always true [-Wtautological-compare]
      if (currentRow + horizontal[j] >= 0 &&
          ~~~~~~~~~~~~~~~~~~~~~~~~~~ ^  ~
src/main.cpp:19:22: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
        currentRow + horizontal[j] < 8 &&
                   ~ ^~~~~~~~~~~~~
src/main.cpp:20:22: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
        currentCol + vertical[j] >= 0 &&
                   ~ ^~~~~~~~~~~
src/main.cpp:20:34: warning: comparison of unsigned expression >= 0 is always true [-Wtautological-compare]
        currentCol + vertical[j] >= 0 &&
        ~~~~~~~~~~~~~~~~~~~~~~~~ ^  ~
src/main.cpp:21:22: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
        currentCol + vertical[j] < 8 &&
                   ~ ^~~~~~~~~~~
src/main.cpp:22:28: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
        board[currentRow + horizontal[j]][currentCol + vertical[j]] == 0
                         ~ ^~~~~~~~~~~~~
src/main.cpp:22:56: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
        board[currentRow + horizontal[j]][currentCol + vertical[j]] == 0
                                                     ~ ^~~~~~~~~~~
src/main.cpp:24:35: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
        currentRow = currentRow + horizontal[j];
                                ~ ^~~~~~~~~~~~~
src/main.cpp:25:35: warning: implicit conversion changes signedness: 'value_type' (aka 'int') to 'unsigned int' [-Wsign-conversion]
        currentCol = currentCol + vertical[j];
                                ~ ^~~~~~~~~~~
10 warnings generated.
./build/main
[01] [24] [09] [00] [00] [26] [37] [00]
[10] [41] [02] [25] [36] [00] [00] [27]
[23] [08] [11] [40] [21] [38] [00] [00]
[64] [03] [22] [35] [00] [00] [28] [00]
[07] [12] [05] [20] [39] [34] [00] [00]
[04] [17] [14] [31] [00] [29] [00] [00]
[13] [06] [19] [16] [33] [00] [00] [00]
[18] [15] [32] [00] [30] [00] [00] [00]

Solution

  • The compiler is saying to you that when you write

    currentRow + horizontal[j] >= 0
    

    you're adding a signed int with an unsigned int, so the signed int is converted in an unsigned int, and so the result of the sum is an unsigned int. An unsigned int is always greater than or equal to zero.

    So this test is always true which is presumably not exactly what you desire.

    Same problem with

    currentCol + vertical[j] >= 0
    

    and more generally, for every sum of signed/unsigned values.

    One option is to define currentRow and currentCol as (signed) int.

    Otherwise you could cast unsigned values appropriately when adding them to signed values

    int{currentRow} + horizontal[j] >= 0