为什么var $编译但var @ doesn&#t; t?

时间:2017-05-13 17:05:33

标签: c gcc operators clang variable-names

拿这段代码:

int main(void)
{
    int var$ = 3;
    printf("%d\n",var$);
}

这正确编译(GCCClangMSVC)并按预期执行时打印3

但是,这段代码:

int main(void)
{
    int var@ = 8;
    printf("%d\n",var@);
}

这不会编译(GCCClangMSVC),错误为stray '@' in program

查看C/C++ Operator List Ctrl + F '为@$),它们都不是运营商。

为什么var$有效但var@不是<?p?

3 个答案:

答案 0 :(得分:4)

查看C11 Specification,关于标识符的第6.4.2节:

  

语义

     

2 标识符是一系列非数字字符(包括下划线_,   指定的小写和大写拉丁字母,以及其他字符和数字   6.2.1中描述的一个或多个实体。小写和大写字母是不同的。   标识符的最大长度没有特定限制。

     

3 标识符中的每个通用字符名称应指定其编码的字符   在ISO / IEC 10646中属于D.1中规定的范围之一。 71)初始字符   不应是指定编码所属字符的通用字符名称   D.2中规定的范围之一。 实现可能允许多字节字符   它不是标识符中出现的基本源字符集的一部分; 哪些字符   它们与通用字符名称的对应关系是实现定义的。

(强调我的)

根据实施定义的行为GCC Manual

  
      
  • 标识符字符。
  •   
     

C和C ++标准允许标识符由“_”和字母数字字符组成。 C ++还允许通用字符名称。 C99及更高版本的C标准允许通用字符名称和实现定义的字符。

     

GCC允许标识符中的“$”字符作为大多数目标的扩展名。无论std=切换如何,都是如此,因为此扩展不能与符合标准的程序冲突。但是,在预处理汇编程序时,默认情况下,美元不是标识符字符。

(强调我的)

再次在Tokenization中,并在Idav1s's answer中提及:

  

作为扩展,GCC将“$”视为一封信。这是为了与某些系统(如VMS)兼容,其中“$”通常用于系统定义的函数和对象名称。 “$”不是严格符合模式的字母,或者如果您指定-$选项。

由于VMS使用了许多系统定义的函数和名为 $ 的对象,因此GCC允许将$作为特定于实现的字符包含在内系统。

C规范未明确允许$@等特殊字符位于标识符中,但实现时可能允许某些字符(例如此处为$) 。例如,GCC允许大多数目标的标识符为$。 Clang也是如此(因为它的大多数实现定义的行为与GCC相同)和MSVC。

答案 1 :(得分:2)

Blame VMS

  

作为延期,海湾合作委员会将'$'视为一封信。这是为了与某些系统(如VMS)兼容,其中“$”通常用于系统定义的函数和对象名称。 '$'不是严格符合模式的字母,或者如果指定 - $选项。请参阅调用。

我稍微修改了您的/// Retrieves the device's location. public final class DeviceLocation: NSObject, CLLocationManagerDelegate { // MARK: - Properties /// Handles the delivery of the device's current location. private let locationManager = CLLocationManager() /// The object responsible for handling the device's location-based updates. public weak var deviceLocationDelegate: DeviceLocationDelegate? // MARK: - Initialization /// Returns an initialized `DeviceLocation` object. public override init() { super.init() locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters } // MARK: - CLLocationManagerDelegate public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { switch status { case .authorizedAlways, .authorizedWhenInUse: startMonitoringLocationChanges() default: return } } public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let location = locations.last else { return } print(location) reverseGeocode(location) deviceLocationDelegate?.deviceLocation(self, didReceiveCoordinate: location.coordinate) } public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print(error) deviceLocationDelegate?.deviceLocation(self, didFailToReceiveCoordinate: error) } // MARK: - Helpers /// Requests access to the user's location while in use. public func requestLocationAccess() { if CLLocationManager.locationServicesEnabled() { locationManager.requestAlwaysAuthorization() } } /// Starts tasks associated with monitoring the device's location. public func startMonitoringLocationChanges() { locationManager.startMonitoringSignificantLocationChanges() } /// Retrieves information for a location from a reverse-geocode query. /// - parameter location: The `CLLocation` instance. private func reverseGeocode(_ location: CLLocation) { let geocoder = CLGeocoder() geocoder.reverseGeocodeLocation(location) { (placemarks, error) in if let geocodeError = error { print(geocodeError) self.deviceLocationDelegate?.deviceLocation(self, didFailToReverseGeocode: geocodeError) return } guard let placemark = placemarks?.last else { return } self.deviceLocationDelegate?.deviceLocation(self, didFinishReverseGeocodeWithLocation: (city: placemark.locality, state: placemark.administrativeArea)) } } } 代码段(以消除我们不关心的警告)并添加严格符合标志here

<dependency>
    <groupId>javax.ws.rs</groupId>
    <artifactId>javax.ws.rs-api</artifactId>
    <version>2.0-m01</version>
</dependency>

因此,如果var$被赋予正确的标记,$ gcc -Wall -std=gnu99 -ansi -pedantic -Werror -O2 -o a.out source_file.c Error(s): source_file.c: In function ‘main’: source_file.c:4:13: error: '$' in identifier or number [-Werror] int var$ = 3; ^ cc1: all warnings being treated as errors 也不会编译。

答案 2 :(得分:1)

嗯,严格来说,var$也无效。

有些编译器允许您使用$作为标识符中的字符,以及a - zA - Z0 - 9_。这是一个非标准的扩展。它很有用,因为其他语言的编译器(我认为包括FORTRAN)允许在标识符中使用$,并且您可能正在尝试编写与其他语言互操作的C代码。显然gcc是允许这种扩展的编译器之一。

允许@的扩展名会更加不寻常。我可能曾经看过一个奇怪的编译器让你使用它,但由于我知道没有用它,对它的需求较少,我想没人会提供它。