假设我有两个具有相同参数类型和名称的函数(不在同一程序中):
ifelse
编译后,它们是否会有相同的错位名称?
返回类型是C ++中受损名称的一部分吗?
答案 0 :(得分:4)
由于整理计划没有标准化,因此这个问题没有单一答案;与实际答案最接近的是查看最常见的整理方案产生的错位名称。据我所知,那些是GCC和MSVC计划,按字母顺序排列,所以......
为了测试这个,我们可以使用一个简单的程序。
#include <string>
#include <cstdlib>
std::string foo(int x) { return "hello"; }
//int foo(int x) { return x; }
int main() {
// Assuming executable file named "a.out".
system("nm a.out");
}
编译并运行GCC或Clang,它将列出它包含的符号。根据取消注释的功能,结果将为:
// GCC:
// ----
std::string foo(int x) { return "hello"; } // _Z3fooB5cxx11i
// foo[abi:cxx11](int)
int foo(int x) { return x; } // _Z3fooi
// foo(int)
// Clang:
// ------
std::string foo(int x) { return "hello"; } // _Z3fooi
// foo(int)
int foo(int x) { return x; } // _Z3fooi
// foo(int)
GCC方案包含的信息相对较少,不包括返回类型:
_Z
表示“功能”。3foo
的名称:::foo
。i
的参数:int
。尽管如此,但是在使用GCC编译时它们是不同的(但不是与Clang编译),因为GCC表明std::string
版本使用cxx11
ABI。
请注意,它仍会跟踪返回类型,并确保签名匹配;它只是不使用函数的受损名称来执行此操作。
为了测试这个,我们可以使用一个简单的程序,如上所述。
#include <string>
#include <cstdlib>
std::string foo(int x) { return "hello"; }
//int foo(int x) { return x; }
int main() {
// Assuming object file named "a.obj".
// Pipe to file, because there are a lot of symbols when <string> is included.
system("dumpbin/symbols a.obj > a.txt");
}
使用Visual Studio编译并运行,a.txt
将列出它包含的符号。根据取消注释的功能,结果将为:
std::string foo(int x) { return "hello"; }
// ?foo@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H@Z
// class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl foo(int)
int foo(int x) { return x; }
// ?foo@@YAHH@Z
// int __cdecl foo(int)
MSVC方案包含整个声明,包括未明确指定的内容:
foo@
::foo
,后跟@
终止。@
。Y
表示“非成员函数”。A
调用约定:__cdecl
。H
代表int
。?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@
(后跟@
终止)std::basic_string<char, std::char_traits<char>, std::allocator<char>>
(简称std::string
)。H
的参数列表:int
(后跟@
终止)。Z
的例外说明符:throw(...)
;除非它是其他东西,否则这个被删除的名称省略,可能是因为MSVC无论如何都忽略了它。如果每个编译单元的声明不相同,这可以让你发牢骚。
通常,大多数编译器在分别以* nix或Windows为目标时会使用其中一种方案(有时是其变体),但这不能保证。例如......
其他编译器使用的方案归功于Agner Fog's PDF。
检查生成的符号,很明显GCC的修改方案不能像对待MSVC那样提供与Machiavelli相同的保护级别。请考虑以下事项:
// foo.cpp
#include <string>
// Simple wrapper class, to avoid encoding `cxx11 ABI` into the GCC name.
class MyString {
std::string data;
public:
MyString(const char* const d) : data(d) {}
operator std::string() { return data; }
};
// Evil.
MyString foo(int i) { return "hello"; }
// -----
// main.cpp
#include <iostream>
// Evil.
int foo(int);
int main() {
std::cout << foo(3) << '\n';
}
如果我们分别编译每个源文件,那么尝试将目标文件链接在一起......
MyString
由于不属于cxx11
ABI,导致MyString foo(int)
被_Z3fooi
修改为int foo(int)
,就像?foo@@YAHH@Z
一样。这允许链接目标文件,并生成可执行文件。试图运行它会导致段错误。?foo@@YA?AVMyString@@H@Z
;因为我们提供 import UIKit
import GoogleMaps
class FirstViewController: UIViewController, CLLocationManagerDelegate {
@IBOutlet weak var mapView: GMSMapView!
var locationManager = CLLocationManager()
var vwGMap = GMSMapView()
override func viewDidLoad() {
super.viewDidLoad()
let camera: GMSCameraPosition = GMSCameraPosition.camera(withLatitude: 22.300000, longitude: 70.783300, zoom: 10.0)
vwGMap = GMSMapView.map(withFrame: self.view.frame, camera: camera)
vwGMap.camera = camera
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
locationManager.distanceFilter = 500
locationManager.requestWhenInUseAuthorization()
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
self.view = vwGMap
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if (status == CLAuthorizationStatus.authorizedWhenInUse)
{
vwGMap.isMyLocationEnabled = true
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let newLocation = locations.last
vwGMap.camera = GMSCameraPosition.camera(withTarget: newLocation!.coordinate, zoom: 15.0)
vwGMap.settings.myLocationButton = true
self.view = self.vwGMap
let marker = GMSMarker()
marker.position = CLLocationCoordinate2DMake(newLocation!.coordinate.latitude, newLocation!.coordinate.longitude)
marker.map = self.vwGMap
}
,链接将失败。考虑到这一点,包含返回类型的修改方案更安全,即使函数不能仅根据返回类型的差异而重载。
答案 1 :(得分:1)
不,我希望他们的错位名称与所有现代编译器相同。更重要的是,在同一程序中使用它们会导致未定义的行为。 C ++中的函数只能在返回类型上有所不同。