ProgramingTip

"서명 된 / 서명되지 않은 불일치"경고 (C4018)를 어떻게 처리합니까?

bestdevel 2020. 10. 30. 08:19
반응형

"서명 된 / 서명되지 않은 불일치"경고 (C4018)를 어떻게 처리합니까?


저는 항상 낮은 메모리 오버 헤드를 염두에두고 C ++로 많은 계산 코드로 작업합니다. STL 컨테이너 (대부분 vector)를 많이 사용하며 거의 모든 단일 함수에서 해당 컨테이너를 반복합니다.

반복 코드는 다음과 가변합니다.

for (int i = 0; i < things.size(); ++i)
{
    // ...
}

그러나 서명되지 않은 불일치 경고 (Visual Studio의 C4018)를 생성합니다.

교체 int일부 unsigned유형 우리가 자주의의 OpenMP 프라그 마를 사용하기 때문에 문제이며, 그것은으로 카운터가 필요합니다 int.

나는 (수백 개의) 경고를 강력하게 놓친 것입니다.

반복자에서 . 반복자는 적절한 장소에 적용 할 때 훌륭하다고 생각합니다. 내가 실행중인 코드는 임의의 액세스 컨테이너를 또는 다른 변경 하지 않은 작업list(반복 반복 int i은 이미 컨테이너에 구애받지) 항상 현재 정책이 필요합니다. 그리고 입력해야하는 추가 코드 (반복자 자체 및 고급)는 문제를 복잡하게 만들어 기본 코드의 단순성을 난독하게 만듭니다.


그것은 모두 당신의 things.size()유형입니다. (C int아닌 C ++에 존재) 일부 "일반적인"부호없는 유형, 즉 x86_32에 해당합니다.size_tunsigned int

연산자 "less"(<)는 부호가 다른 두 피연산자에 존재하지 않습니다. 표준은 컴파일러가 암시 적 부호 변환을 수행 할 수 있는지 여부를 지정합니다. 따라서 부호있는 숫자를 부호없는 취급하고 경고를 내 보냅니다.

다음과 같이 쓰는 것이 맞을 것입니다.

for (size_t i = 0; i < things.size(); ++i) { /**/ }

또는 더 빨리

for (size_t i = 0, ilen = things.size(); i < ilen; ++i) { /**/ }

이상적으로는 다음과 같은 구조를 대신 사용합니다.

for (std::vector<your_type>::const_iterator i = things.begin(); i != things.end(); ++i)
{
  // if you ever need the distance, you may call std::distance
  // it won't cause any overhead because the compiler will likely optimize the call
  size_t distance = std::distance(things.begin(), i);
}

이 코드가 갑자기 컨테이너에 구애받지 않는 깔끔한 이점이 있습니다.

문제와 관련 그리고하여 사용하는 일부 라이브러리 가 더 적합한 int에서 사용해야 하는 경우 unsigned intAPI가 지저분합니다. 어쨌든, 그것이 int항상 긍정적 이라고 확신한다면 다음과 같이 할 수 있습니다.

int int_distance = static_cast<int>(distance);

컴파일러에 대한 의도를 명확하게 지정합니다. 더 이상 경고로 인해 버그가 발생했습니다.


당신은 / 반복자를 사용하지 않습니다 당신은 /하지 않을 수 사용없는 경우 수없는 경우 std::size_t루프 인덱스를 들어,을 .size()int문서 가정이와 CHAPTER 2이 명시 적으로 컴파일러 경고를 침묵 않는 CHAPTER 2 기능 현관.

#include <cassert>
#include <cstddef>
#include <limits>

// When using int loop indexes, use size_as_int(container) instead of
// container.size() in order to document the inherent assumption that the size
// of the container can be represented by an int.
template <typename ContainerType>
/* constexpr */ int size_as_int(const ContainerType &c) {
    const auto size = c.size();  // if no auto, use `typename ContainerType::size_type`
    assert(size <= static_cast<std::size_t>(std::numeric_limits<int>::max()));
    return static_cast<int>(size);
}

그런 다음 다음과 같이 루프를 작성합니다.

for (int i = 0; i < size_as_int(things); ++i) { ... }

이 함수 템플릿의 인스턴스화는 거의 확실하게 인라인됩니다. 디버그 빌드에서는 가정이 확인됩니다. 릴리스 빌드에서는 사용하는 것처럼 size ()를 직접 호출하는 것처럼 코드가 빠입니다. 두 버전 모두 컴파일러 경고를 생성하지 관용적 루프에 대한 약간의 수정일뿐입니다.

릴리스 버전 버전 가정 실패를 선택해야합니다. 만약 문으로 대체 할 수 있습니다 std::out_of_range("container size exceeds range of int").

이렇게하면 부호있는 / 부호없는 비교와 인 sizeof(int)! = sizeof(Container::size_type)문제가 모두 해결됩니다. 모든 경고를 활성화 된 상태로두고이를 사용하여 코드의 다른 부분에서 실행할 수 있습니다.


당신이 사용할 수있는 :

  1. size_t 유형, 경고 메시지 제거
  2. 반복자 + 거리 (예 : 첫 번째 힌트)
  3. 반복자 만
  4. 함수 객체

예를 들면 :

// simple class who output his value
class ConsoleOutput
{
public:
  ConsoleOutput(int value):m_value(value) { }
  int Value() const { return m_value; }
private:
  int m_value;
};

// functional object
class Predicat
{
public:
  void operator()(ConsoleOutput const& item)
  {
    std::cout << item.Value() << std::endl;
  }
};

void main()
{
  // fill list
  std::vector<ConsoleOutput> list;
  list.push_back(ConsoleOutput(1));
  list.push_back(ConsoleOutput(8));

  // 1) using size_t
  for (size_t i = 0; i < list.size(); ++i)
  {
    std::cout << list.at(i).Value() << std::endl;
  }

  // 2) iterators + distance, for std::distance only non const iterators
  std::vector<ConsoleOutput>::iterator itDistance = list.begin(), endDistance = list.end();
  for ( ; itDistance != endDistance; ++itDistance)
  {
    // int or size_t
    int const position = static_cast<int>(std::distance(list.begin(), itDistance));
    std::cout << list.at(position).Value() << std::endl;
  }

  // 3) iterators
  std::vector<ConsoleOutput>::const_iterator it = list.begin(), end = list.end();
  for ( ; it != end; ++it)
  {
    std::cout << (*it).Value() << std::endl;
  }
  // 4) functional objects
  std::for_each(list.begin(), list.end(), Predicat());
}

C ++ 11에 대한 다음 솔루션을 제안 할 수도 있습니다.

for (auto p = 0U; p < sys.size(); p++) {

}

(C ++는 auto p = 0에 대해 충분히 똑똑하지 않습니다 p = 0U를 넣어야합니다 ....)


더 나은 아이디어를 드릴게요

for(decltype(things.size()) i = 0; i < things.size(); i++){
                   //...
}

decltype 이다

선언 된 엔터티 유형 또는 식의 유형 및 값 범주를 검사합니다.

의 유형을 따라서 추론 things.size()하고와 i같은 유형이됩니다 things.size(). 따라서 i < things.size()경고없이 실행됩니다.


비슷한 문제가있었습니다. size_t 사용이 작동하지 않았습니다. 나는 나를 위해 일한 다른 것을 시도했습니다. (아래)

for(int i = things.size()-1;i>=0;i--)
{
 //...
}

난 그냥 할거야

int pnSize = primeNumber.size();
for (int i = 0; i < pnSize; i++)
    cout << primeNumber[i] << ' ';

참고 URL : https://stackoverflow.com/questions/7443222/how-do-i-deal-with-signed-unsigned-mismatch-warnings-c4018

반응형