[英]Why does the C++ modulo operator return 0 for -1 % str.size()?
我很困惑為什么下面的代碼會產生這個 output:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int i = -1;
string s = "abc";
int j = s.size();
int x = 1 % 3;
int y = i % j;
int z = i % s.size();
cout << s.size() << endl; // 3
cout << x << endl; // 1
cout << y << endl; // -1
cout << z << endl; // 0
}
為什么z = 0? 跟選角有關系嗎?
這里真正發生了什么:
int z = i % s.size();
is i
被轉換為size_t
因為另一邊s.size()
是size_t
。 與int
不同, size_t
是無符號的; 也就是說,該值被解釋為正數。
檢查這一行的output:
std::cout << (size_t)-1 << std::endl;
看看 -1 變成了什么。
因此,將您的代碼簡化為一個最小的示例,您會問為什么會打印0
:
#include <iostream>
#include <string>
int main()
{
int a = -1;
std::string::size_type b = 3;
int c = a % b;
std::cout << c << '\n';
}
這里有問題的主要操作是這樣的:
a % b
按照標准,
5.6 乘法運算符 [expr.mul]
- * 和 / 的操作數應具有算術或非范圍枚舉類型; % 的操作數應具有整數或無范圍枚舉類型。 通常的算術轉換在操作數上執行並確定結果的類型。
那么..那些“通常的算術轉換”呢? 這是為了在執行實際操作之前將兩個操作數的類型匹配為一個通用類型。 以下是按順序考慮的:
對於有效地說明這一點來說,這是很多合法化的:
signed int
和一個std::string::size_type
std::string::size_type
的秩大於signed int
signed int
操作數在請求操作之前被轉換為std::string:size_type
類型。所以剩下的就是轉換,也就是說,還有一個合法化:
4.7 積分轉換[conv.integral]
- 如果目標類型是無符號的,則結果值是與源 integer 一致的最小無符號 integer(模 2 n ,其中 n 是用於表示無符號類型的位數)。 [注意:在二進制補碼表示中,這種轉換是概念性的,位模式沒有變化(如果沒有截斷)。 ——尾注]
這意味着,在 32 位std::string::size_type
平台上,您將獲得 2 32 -1 作為來自int
(-1) 的轉換值。
意思是...
4294967295 % 3
這是......零。 如果std::string::size_type
是 64 位,那么上面的一切都保持不變,除了最后的計算,這將是:
18446744073709551615 % 3
@GhaziMajdoub 的回答是正確的,但是 - 你為什么不讓編譯器告訴你發生了什么?
讓我們使用標志來啟用徹底和詳細的 g++ 警告......
$ g++ -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy \
-Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations \
-Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual \
-Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel \
-Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused -o a a.cpp
a.cpp: In function ‘int main()’:
a.cpp:12:13: error: conversion to ‘std::__cxx11::basic_string<char>::size_type’ {aka
‘long unsigned int’} from ‘int’ may change the sign of the result
[-Werror=sign-conversion]
12 | int z = i % s.size();
| ^
cc1plus: all warnings being treated as errors
a.cpp: In function ‘int main()’:
a.cpp:12:13: warning: conversion to ‘std::__cxx11::basic_string<char>::size_type’
{aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-
conversion]
12 | int z = i % s.size();
| ^
你有它: i
被轉換為long unsigned int
,所以它不再是-1
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.