"서명 된 / 서명되지 않은 불일치"경고 (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_t
unsigned 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 int
API가 지저분합니다. 어쨌든, 그것이 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)
문제가 모두 해결됩니다. 모든 경고를 활성화 된 상태로두고이를 사용하여 코드의 다른 부분에서 실행할 수 있습니다.
당신이 사용할 수있는 :
- size_t 유형, 경고 메시지 제거
- 반복자 + 거리 (예 : 첫 번째 힌트)
- 반복자 만
- 함수 객체
예를 들면 :
// 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] << ' ';
'ProgramingTip' 카테고리의 다른 글
memcpy (0,0,0)을 수행하는 것이 안전을 수행합니까? (0) | 2020.10.30 |
---|---|
"값 유형과 'null'의 가능한 비교"는 어떻게해야합니까? (0) | 2020.10.30 |
공급 업체별 의사 요소 / 클래스를 하나의 규칙 세트로 결합 할 수없는 이유는 무엇입니까? (0) | 2020.10.30 |
Spring 5.0.3 RequestRejectedException : URL이 갑자기 발생하지 않아 요청이 거부되었습니다. (0) | 2020.10.30 |
ASPXAUTH 쿠키 란 무엇입니까? (0) | 2020.10.30 |