“서명 된 / 서명되지 않은 불일치”경고 (C4018)를 어떻게 처리합니까? 염두에두고 C ++로

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

반복 코드는 다음과 같습니다.

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

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

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

나는 (수백 개의) 경고를 억제하려고하는데 문제에 대한 우아한 해결책을 놓친 것 같아 두렵다.

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



답변

그것은 모두 당신의 things.size()유형입니다. 는 int아니지만 size_t(C 가 아닌 C ++에 존재) 일부 “일반적인”부호없는 유형, 즉 unsigned intx86_32에 해당합니다.

연산자 “less”(<)는 부호가 다른 두 피연산자에 적용될 수 없습니다. 그러한 opcode는 없으며 표준은 컴파일러가 암시 적 부호 변환을 수행 할 수 있는지 여부를 지정하지 않습니다. 따라서 부호있는 숫자를 부호없는 것으로 취급하고 경고를 내 보냅니다.

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

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문서 가정이와 변환이 명시 적으로 컴파일러 경고를 침묵 않는 변환 기능.

#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 ()를 직접 호출 한 것처럼 코드가 빠릅니다. 두 버전 모두 컴파일러 경고를 생성하지 않으며 관용적 루프에 대한 약간의 수정일뿐입니다.

릴리스 버전에서도 가정 실패를 포착하려면 어설 션을 다음과 같은 if 문으로 대체 할 수 있습니다 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--)
{
 //...
}