关于 y0 y1 yn 变量名冲突说法的指正

前言

本文主要讲述变量名冲突的问题。

\\color{orange}免责声明

由于版本问题,您遇到的情况可能与我所讲述的不符,一切以本机版本为准,如果您遇到了其他问题,欢迎在评论区留下您的观点或遇到的问题。

即使现在变量名问题已经得到解决,我仍不建议大家在 NOI 系列比赛中使用这些变量名。

本人所用配置是:

  • Microsoft: Windows 10
    • Dev C++: 5.11
    • MingW64: 4.9.2
  • Linux stu: 20.04
    • Genay:1.36
    • MingW64:Ubuntu 9.4.0
  • Luogu IDE: C++14(GCC 9)

正文

引入

在机房颓的时候突然发现自己之前写的一道学校改编的入门考试题(原题在这里),

我这样写:

cpp 复制代码
double len(double x1, double y1, double x2, double y2){
    return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

按照现在的一般说法,这应该会 CE,因为 x1 y1 不能用作变量名。

但是它诡异地 AC 了。

?不是说不行吗?

于是 cao2333 开始了查资料 -> 验证 -> 不对 -> 查资料的循环......

前置知识:

  • #ifdef Value:和日常写代码时的 if() 很像,如果 Value 值为 1 则会执行下面的语句。
  • #ifndef Value:与 #ifdef 恰好相反,当后面的 Value 条件不成立时才会执行。
  • #endif:表示终止条件判断,与 #ifdef 和 #ifndef 连用。
  • #include<filename> 导入头文件
  • #define A B 宏定义,告诉编译器遇到 A 就当成 B。
  • #undef A 表示取消 #define 的宏定义。

cmath

cmath 文件是标准的数学库。在这个库中,包括了 abs(绝对值)sin cos tan (三角函数)ceil floor(向上/向下取整)等等十分好用的函数的指向。

有很多说法指出,x1 等变量名被占用是 cmath 头文件的锅。那么我们扒一下他的代码:

P.S. 省略 1600 多行代码。

......算了,还是用搜索吧。

搜索结果:未找到"x1"。

很好看来这个问题并没有出在 cmath 文件。

那么为什么很多人加了 cmath 会有问题、不加就没问题呢?

我们仔细审视一下 cmath 文件,发现这里的很多函数用几个模糊的大写字母来计算,大部分函数只有不到十行,这显然不足以完成仅仅推导式就要十几行的数学函数。

实际上,cmath 文件并不提供 部分 数学函数的解决办法,它的性质与 bits/stdc++.h 相似,都是将一些零散的头文件合并,并将深层头文件内容 、本文件中的额外附加 以及执行条件一并添加到你编写的程序中。

因此如果深层的头文件出现问题,依赖该文件的其他文件也会报错。

在 cmath 的开头部分中,我们找到以下代码:

cpp 复制代码
#pragma GCC system_header

#include <bits/c++config.h>
#include <bits/cpp_type_traits.h>
#include <ext/type_traits.h>
#include <math.h>

看来问题就出在这几个头文件里了。

math.h

经过搜索大法,问题出在 C:\Program Files (x86)\Dev-Cpp\MinGW64\x86_64-w64-mingw32\include\math.h 上。

math.h 文件中,存储了部分函数的定义、运算方式 和 大部分数学函数的指向 。包括但不限于 abs sin cos 等。

然后观察到:

cpp 复制代码
_CRTIMP double __cdecl j0 (double) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
_CRTIMP double __cdecl j1 (double) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
_CRTIMP double __cdecl jn (int, double) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
_CRTIMP double __cdecl y0 (double) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
_CRTIMP double __cdecl y1 (double) __MINGW_ATTRIB_DEPRECATED_MSVC2005;
_CRTIMP double __cdecl yn (int, double) __MINGW_ATTRIB_DEPRECATED_MSVC2005;

这是现在的代码。如果你是报错的话,这一段大概率长这样:

cpp 复制代码
_CRTIMP double __cdecl j0 (double);
_CRTIMP double __cdecl j1 (double);
_CRTIMP double __cdecl jn (int, double);
_CRTIMP double __cdecl y0 (double);
_CRTIMP double __cdecl y1 (double);
_CRTIMP double __cdecl yn (int, double);

并不知道两段有什么区别

总之,可能是 MinGW 不知道何时更新了,现在定义变量名使用 x1 y1 x0 y0 都没有问题了。


拓展

虽然现在可以用这些变量名了,但是我还是有一些问题和有趣的发现:

这几个函数是干什么用的?

这个我已经没有时间和精力去递归式查找了,于是在这里贴出 Bing 搜索的结果:

\(j0,j1,jn\) 用于返回第一类贝塞尔函数解;

\(y0,y1,yn\) 用于返回第二类贝塞尔函数解;

什么是贝塞尔函数?

似乎在计算机学中还没有广泛使用?如果感兴趣的话可以去看看偶,没准你是下一个新算法的发明者。

为什么现在没事了?

是啊为什么?

由于机房的网是断开的,只能上几个限定网站,因此我也不知道 Bing 到的这个结果 中的解决办法是什么......

源代码打表

在 math.h 函数中:

cpp 复制代码
#define M_E		2.7182818284590452354
#define M_LOG2E		1.4426950408889634074
#define M_LOG10E	0.43429448190325182765
#define M_LN2		0.69314718055994530942
#define M_LN10		2.30258509299404568402
#define M_PI		3.14159265358979323846
#define M_PI_2		1.57079632679489661923
#define M_PI_4		0.78539816339744830962
#define M_1_PI		0.31830988618379067154
#define M_2_PI		0.63661977236758134308
#define M_2_SQRTPI	1.12837916709551257390
#define M_SQRT2		1.41421356237309504880
#define M_SQRT1_2	0.70710678118654752440

呵,想必大家都知道这片源代码在干什么吧......

赤裸裸的打表啊!

两个 math.h

在搜索时,C:\Program Files (x86)\Dev-Cpp\MinGW64\lib\gcc\x86_64-w64-mingw32\4.9.2\include\c++\tr1 路径下还有一份 math.h 文件。这份文件中有大量的 using tr1::...:: 代码。应该是 tr1 的实现代码。不知道是做什么的,今天按下不表。

变量名通缉单

在 cmath 文件中,断断续续出现了下列代码:
\\color{blue}过长,已折叠

cpp 复制代码
#undef abs
#undef div
#undef acos
#undef asin
#undef atan
#undef atan2
#undef ceil
#undef cos
#undef cosh
#undef exp
#undef fabs
#undef floor
#undef fmod
#undef frexp
#undef ldexp
#undef log
#undef log10
#undef modf
#undef pow
#undef sin
#undef sinh
#undef sqrt
#undef tan
#undef tanh

#undef fpclassify
#undef isfinite
#undef isinf
#undef isnan
#undef isnormal
#undef signbit
#undef isgreater
#undef isgreaterequal
#undef isless
#undef islessequal
#undef islessgreater
#undef isunordered

#undef acosh
#undef acoshf
#undef acoshl
#undef asinh
#undef asinhf
#undef asinhl
#undef atanh
#undef atanhf
#undef atanhl
#undef cbrt
#undef cbrtf
#undef cbrtl
#undef copysign
#undef copysignf
#undef copysignl
#undef erf
#undef erff
#undef erfl
#undef erfc
#undef erfcf
#undef erfcl
#undef exp2
#undef exp2f
#undef exp2l
#undef expm1
#undef expm1f
#undef expm1l
#undef fdim
#undef fdimf
#undef fdiml
#undef fma
#undef fmaf
#undef fmal
#undef fmax
#undef fmaxf
#undef fmaxl
#undef fmin
#undef fminf
#undef fminl
#undef hypot
#undef hypotf
#undef hypotl
#undef ilogb
#undef ilogbf
#undef ilogbl
#undef lgamma
#undef lgammaf
#undef lgammal
#undef llrint
#undef llrintf
#undef llrintl
#undef llround
#undef llroundf
#undef llroundl
#undef log1p
#undef log1pf
#undef log1pl
#undef log2
#undef log2f
#undef log2l
#undef logb
#undef logbf
#undef logbl
#undef lrint
#undef lrintf
#undef lrintl
#undef lround
#undef lroundf
#undef lroundl
#undef nan
#undef nanf
#undef nanl
#undef nearbyint
#undef nearbyintf
#undef nearbyintl
#undef nextafter
#undef nextafterf
#undef nextafterl
#undef nexttoward
#undef nexttowardf
#undef nexttowardl
#undef remainder
#undef remainderf
#undef remainderl
#undef remquo
#undef remquof
#undef remquol
#undef rint
#undef rintf
#undef rintl
#undef round
#undef roundf
#undef roundl
#undef scalbln
#undef scalblnf
#undef scalblnl
#undef scalbn
#undef scalbnf
#undef scalbnl
#undef tgamma
#undef tgammaf
#undef tgammal
#undef trunc
#undef truncf
#undef truncl

实测发现,在这张列表里涉及到的所有 #undef 后面的命名 全部有对应函数 ,都不能作为变量名。

后记

其实也算是颓了一个下午。有一种探案的感觉呢。不过在查资料的过程中,我发现了这样一个问题:

大家要么是查到资料解决问题就好,要么是发现问题避开问题,很少的巨佬会身先士卒追根究底、不找到根因不罢休。

我也不是什么巨佬啦,我的调查就到这里了,如果有很多人支持的话,我应该会出第二期 QwQ,如果有巨佬收到启发,希望诸位巨佬也要坚持到底呀!


\\\color{green}The\\;\\;End \\

相关推荐
无咎.lsy1 小时前
《机器学习》笔记
笔记·机器学习
坤坤子吖2 小时前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习
蒸蒸yyyyzwd4 小时前
后端相关学习笔记。
笔记·学习
旖旎夜光5 小时前
【C++ 基础入门】C++ 多态(上):虚函数、重写、override/final 与抽象类
开发语言·c++·笔记·学习
Oll Correct6 小时前
Adobe illustrator 案例十二:视频播放(Media & Video)图标绘制
笔记·ui·adobe·illustrator
叼烟扛炮7 小时前
Linux 学习笔记(五十四):内网穿透实战——用 frp 让外网访问你的私人电脑
linux·服务器·网络·笔记·学习
旖旎夜光8 小时前
【C++ 基础入门】C++ 继承(上):概念、切片、隐藏、默认成员函数与友元
c++·笔记·学习
叼烟扛炮8 小时前
[LangChain] 学习笔记(05):提示词模板(Prompt)与少样本注入(Few-Shot)实战
linux·人工智能·笔记·学习·langchain·prompt
La Pulga21 小时前
【FreeRTOS源码学习笔记】任务延时列表
笔记·mcu·学习·嵌入式·freertos·实时操作系统
Peter-OK1 天前
PostgreSQL学习笔记(入门-进阶-精通说明)
笔记·学习·postgresql