변수 이름을 숫자로 시작할 수없는 이유는 무엇입니까?


136

"왜 변수 이름을 숫자로 시작할 수 없는가?"라는 질문을하면서 얼마 전 새로운 C ++ 개발자와 함께 일하고있었습니다.

일부 숫자에는 텍스트가있을 수 있으며 (123456L, 123456U), 어떤 양의 알파 문자가있는 모든 것이 변수 이름이라고 생각하면 불가능할 것입니다.

정답입니까? 더 이상의 이유가 있습니까?

string 2BeOrNot2Be = "that is the question"; // Why won't this compile?

15
그리고 왜 그들 안에 공백이있을 수 없습니까?
Tim

4
이 문제는 첫 번째 매크로 어셈블러로 돌아 가지 않으면 C ++보다 20 년 이상 앞서 있습니다.
Ken Gentle

2
FORTH에서는 할 수 있습니다. AFAIK에는 00을 스택으로 푸시 하는 단어가 있습니다. 다른 하나는 0=0이 스택에 있는지 확인하는 것입니다.
Ingo

12
이 질문이 왜 그렇게 대중적이고 대답이 그렇게 잘못 되었습니까? 많은 언어에서 변수를 숫자로 시작할 수 있습니다. C ++은 특정 모호성을 피하는 편리한 제한입니다. 때로는 너무 잘못된 방법으로 나를 놀라게합니다.
david.pfx

5
이 질문이 오늘 SO에 관한 것이라면, 그것은 의견에 기반을두고 종료 될 것입니다. 이것을 물어 주셔서 감사합니다.
Boon

답변:


116

따라서 숫자 문자열은 유효한 식별자 일뿐만 아니라 유효한 식별자 일 것입니다.

int 17 = 497;
int 42 = 6 * 9;
String 1111 = "Totally text";

37
변수가 숫자 일 수 없다고 말하면 어떨까요? 그리고 뭐?
Pyrolistical

6
가능한 경우 어휘 분석기가 규칙을 사용하여 식별자를 선택하는 데 정규 표현식을 작성하는 데 시간이 더 오래 걸렸습니다. 따라서 다른 답변.
skiphoppy

39
숫자 + 알파 여야한다면 String 0x123 = "Hello World"를 계속 수행 할 수 있습니다. 변수 이름이 "유효한 숫자 지정으로 구문 분석하지 않는 숫자 + 알파"라고 말하지 않는 한, 그것은 어리 석습니다.
eaolson

4
컴파일러를 신경 쓰지 마십시오 . 언어를 사용 하는 사람들 변수 이름을 숫자와 쉽게 (한 눈에) 구별 할 수 있어야합니다. 첫 번째 문자가 말하지 않은 경우-대신 단어의 나머지 부분을 검색하여 숫자가 아닌 알파가 있는지 확인 해야하는 경우 코드를 읽기가 더 어려워집니다.
오는 폭풍

10
@eaolson : 나는 시작 진수 번호에 해당 규칙을 적용 어셈블러와 함께 작업 한 A- F와 함께 끝났다 h. Bach 's Two Part Invention # 13 (논리 이름? Bach) 의 음악 데이터를 가리 키도록 레이블을 정의하려고 처음으로 넘어갔습니다 .
supercat

116

이것에 대해 생각해보십시오.

int 2d = 42;
double a = 2d;

무엇입니까? 2.0? 또는 42?

힌트, 만약 당신이 그것을 얻지 못하면, 숫자 뒤의 d는 이중 리터럴 이전의 숫자를 의미합니다.


11
이것은 C89 표준 IIRC 인 [상대적으로] 늦게 나오는 표기법 ( "double"의 경우 "d")입니다. 이 구문이 언어로되어 있으면 식별자의 선행 숫자는 불가능하지만 숫자가 식별자를 시작할 수없는 이유는 아닙니다.
Ken Gentle

1
dC ++에서 유효한 부동 리터럴 접미사가 아닙니다. 부동 리터럴은 기본적으로 배가 되므로 float 또는 long double 리터럴이 필요한 경우 f또는 사용할 수 있습니다 l.
CB Bailey

1
Java에 대한 것이며 원래 질문은 C ++에 관한 것이지만 Java와 같은 다른 많은 언어에도 적용됩니다. 하지만 동의합니다. 이것이 식별자가 숫자로 시작할 수없는 원래의 이유는 아닙니다.
Pyrolistical

50

이제는 컨벤션이지만 기술 요구 사항으로 시작되었습니다.

예전에는 FORTRAN이나 BASIC과 같은 언어 파서는 공백을 사용할 필요가 없었습니다. 따라서 기본적으로 다음은 동일합니다.

10 V1=100
20 PRINT V1

10V1=100
20PRINTV1

이제 숫자 접두사가 허용되었다고 가정하십시오. 이것을 어떻게 해석 하시겠습니까?

101V=100

같이

10 1V = 100

또는

101 V = 100

또는

1 01V = 100

그래서 이것은 불법입니다.


1
작은 nit : 행 번호는 1-6 열에 있어야하고 실행 코드는 8 열 다음에 DO 10 I=1,50있어야했습니다. 반면 DO1 0I=1,50에 쉼표 대신 마침표를 사용하면 명령문이 다음과 같이 지정됩니다. 라는 부동 소수점 변수 DO10I.
supercat

재미있는 설명! 그것은 더 오래된 언어들에게는 이해가되지만, 왜 우리가 왜 파이썬이나 JavaScript 또는 R과 같은 언어들에 대한 디자인 선택을 계속했는지 궁금해합니다.
Charles Clayton

나는 이것을 BASIC으로 분명히 기억하고 이것이 아마도 가장 실용적인 실제 이유라고 생각합니다. 기술적으로, 나는 그것이 실제로 초기 어셈블리 언어로 돌아갈 수 있다는 것을 모호하게 기억합니다. 그래도 어셈블러가 무엇인지 잘 모르겠으며 잘못되었을 수 있습니다.
브라이언 챈들러

42

컴파일하는 동안 어휘 분석에서 역 추적을 피할 수 있기 때문입니다. 다음과 같은 변수

Apple;

컴파일러는 문자 'A'를 만나면 바로 식별자임을 알 수 있습니다.

그러나 다음과 같은 변수는

123apple;

컴파일러는 'a'가 될 때까지 숫자 또는 식별자인지 결정할 수 없으므로 결과적으로 역 추적이 필요합니다.


2
내 컴파일러 디자인 클래스를 기억하여 대답하려면이 대답은 똑바로 진행됩니다! Kudos
nehem

15

컴파일러 / 파서 / 어휘 분석기는 오래 전에 오래 전에 사용되었지만 컴파일 단위의 숫자 문자가 리터럴인지 식별자인지를 명확하게 결정하는 데 어려움이 있다고 생각합니다.

공간이 중요하지 않은 언어 (ALGOL 및 올바르게 기억하면 원래 FORTRAN과 같은)는 해당 이유로 식별자를 시작하기 위해 숫자를 받아 들일 수 없습니다.

이것은 저장 또는 숫자 기반을 나타내는 특수 표기법 이전으로 거슬러 올라갑니다.


9

식별자를 숫자로 시작하는 것이 편리하다는 데 동의합니다. 한두 사람이 식별자에 밑줄을 붙여서 이러한 제한을 해결할 수 있다고 언급했지만 실제로는 추악합니다.

문제의 일부는 0xdeadbeef와 같은 숫자 리터럴에서 비롯된 것으로 생각되므로 숫자로 시작할 수있는 식별자 규칙을 기억하기가 어렵습니다. 이를 수행하는 한 가지 방법은 키워드 또는 숫자 리터럴이 아닌 [A-Za-z _] +와 일치하는 항목을 허용하는 것입니다. 문제는 0xdeadpork와 같은 이상한 것들을 허용하지만 0xdeadbeef는 허용하지 않는다는 것입니다. 궁극적으로 우리는 모든 육류에 공정해야한다고 생각합니다.

C를 처음 배울 때 변수 이름에 대한 규칙이 임의적이고 제한적이라는 느낌이 들었습니다. 무엇보다도 그들은 기억하기가 어려워서 배우려고 포기했습니다. 방금 옳은 느낌을 받았고 꽤 잘 작동했습니다. 이제 더 많이 배웠으므로 그리 나쁘지 않고 마침내 올바르게 배우기 시작했습니다.


8
LOL- "문제는 0xdeadpork와 같은 이상한 것들을 허용하지만 0xdeadbeef는 허용하지 않는다는 것입니다. 궁극적으로, 우리는 모든 육류에 공정해야한다고 생각합니다.
mr-euro

6

토큰을 구문 분석 할 때 첫 문자 만보고 식별자 또는 리터럴인지 확인한 후 처리를 위해 올바른 함수로 보내야합니다. 이것이 성능 최적화입니다.

다른 옵션은 리터럴이 아닌지 확인하고 식별자 도메인을 리터럴을 제외한 유니버스로 두는 것입니다. 그러나 이렇게하려면 모든 토큰의 모든 특성을 검사하여 분류 방법을 알아야합니다.

또한 문체 의미 식별자가 니모닉이어야하므로 숫자보다 단어를 기억하기가 훨씬 쉽습니다. 다음 수십 년 동안 스타일을 설정하여 많은 독창적 인 언어가 쓰여졌을 때, 그들은 "2"를 "to"로 대체 할 생각을하지 않았습니다.


6

변수 이름은 다음과 같은 몇 가지 문제를 일으킬 수 있으므로 숫자로 시작할 수 없습니다.

int a = 2;
int 2 = 5;
int c = 2 * a; 

c의 가치는 무엇입니까? 4 또는 10입니다!

다른 예시:

float 5 = 25;
float b = 5.5;

처음 5는 숫자이거나 객체입니다 (. 연산자) 둘째 5와 비슷한 문제가 있습니다.

다른 이유가있을 수 있습니다. 따라서 변수 이름의 시작 부분에 숫자를 사용해서는 안됩니다.


식별자에 숫자가 아닌 문자가 하나 이상 있어야하더라도 문자가 포함 된 숫자 형식에 영숫자가 아닌 문자도 포함해야합니다 (예 : 0x1234를 $ 1234로 쓰고 1E6을 써야 함) 1.E6 또는 1.0E6] 또는 다른 유효한 식별자 이름과 잘못된 식별자 이름을 갖습니다.
supercat 2016 년

4

변수 이름을 시작하기 위해 숫자를 사용하면 컴파일 또는 인터프리터 동안 오류 점검이 훨씬 더 복잡해집니다.

숫자처럼 시작한 변수 이름을 사용하면 언어 설계자에게 큰 문제가 발생할 수 있습니다. 소스 코드 구문 분석 중에 컴파일러 / 인터프리터가 변수 이름이 예상되는 숫자로 시작하는 토큰을 발견 할 때마다 토큰이 실제로 변수인지 또는 오류인지 판별하기 위해 거대하고 복잡한 규칙 세트를 검색해야합니다. . 언어 파서에 추가 된 복잡성은이 기능을 정당화하지 못할 수도 있습니다.

내가 기억할 수있는 한 (약 40 년), 숫자를 사용하여 변수 이름을 시작할 수있는 언어를 사용한 적이 있다고 생각하지 않습니다. 나는 이것이 적어도 한 번은 끝났다고 확신한다. 어쩌면 여기 누군가가 실제로 이것을 어딘가에서 보았을 것입니다.


1
그렇게 어렵지 않습니다. 어휘 단계를 더 어렵게 만듭니다. 물론 컴파일러를 가져 왔을 때 어휘 스캔이 총 컴파일 시간의 4 분의 1을 차지할 수 있다고 들었습니다.
David Thornley

4

여러 사람들이 알고 있듯이 변수 이름의 유효한 형식에 대한 많은 역사적인 수하물이 있습니다. 그리고 언어 디자이너는 항상 새로운 언어를 만들 때 알고있는 것에 영향을받습니다.

즉, 언어가 변수 이름을 숫자로 시작하는 것을 허용하지 않는 거의 대부분은 언어 디자인의 규칙이기 때문입니다. 그러한 간단한 규칙으로 인해 언어의 구문 분석과 어휘 분석이 훨씬 쉬워 지기도합니다. 그러나 모든 언어 디자이너가 이것이 진짜 이유라는 것을 알고있는 것은 아닙니다. 최신 렉싱 도구가 도움이됩니다. 허용 가능한 것으로 정의하면 구문 분석 충돌이 발생하기 때문입니다.

OTOH, 귀하의 언어가 변수 이름을 예고하기 위해 고유하게 식별 가능한 문자를 가지고 있다면, 숫자로 시작하도록 언어를 설정할 수 있습니다. 변수 이름에 공백을 허용하기 위해 유사한 규칙 변형을 사용할 수도 있습니다. 그러나 결과 언어는 널리 사용되는 기존의 언어와 전혀 유사하지 않을 수 있습니다.

변수가 숫자로 시작하고 공백이있는 HTML 템플리트 언어의 예를 보려면 Qompose보십시오 .


1
실제로, 식별자를 표시하는 문자를 가질 수있는 여러 언어가 있습니다. 그것들은 "sigils"라고 불리며 당신은 그것들을 Perl과 PHP로 가지고 있습니다.
Jason Baker

PHP에서 변수 이름을 숫자로 시작할 수 없다는 것을 제외하고 언어 규칙은 그것을 금지합니다. :-) 그러나 Qompose에서 정확히 같은 이유로 할 수 있습니다.
staticsan

4

키워드와 식별자가 숫자 문자로 시작하도록 허용 한 경우, 어휘 분석기 (컴파일러의 일부)는 훨씬 더 복잡하고 느리게되지 않으면 서 숫자 리터럴의 시작과 키워드를 쉽게 구별 할 수 없었습니다.


2
렉싱 프로세스는 병목 현상이 거의 없습니다. 물론, 식별자 토큰의 정규식을 더 복잡하게 만들지 만 여전히 초고속 DFA 일 수 있습니다. 그 런타임은 다른 대부분의 컴파일러가 수행 해야하는 작업과 비교할 때 땅콩입니다.

4

제한은 임의적입니다. 다양한 리스프를 사용하면 기호 이름을 숫자로 시작할 수 있습니다.


4

COBOL을 사용하면 변수를 숫자로 시작할 수 있습니다.


2

언어 디자이너가 규칙으로 만들었 기 때문에 C ++은 그것을 가질 수 없습니다. 당신이 당신의 자신의 언어를 창조한다면, 당신은 확실히 그것을 허용 할 수 있지만, 당신은 아마 그들이했던 것과 같은 문제에 부딪 히고 그것을 허용하지 않기로 결정할 것입니다. 문제를 일으킬 수있는 변수 이름의 예 :

0x, 2d, 5555


이 제한은 그런 종류의 구문이 허용되지 않는 언어로 유지됩니다.
Jason Baker

2

구문 규약 완화에 대한 주요 문제점 중 하나는 코딩 프로세스에인지 부조화를 도입한다는 것입니다. 코드에 대해 어떻게 생각하는지는 이것이 소개 할 명확성 부족에 큰 영향을받을 수 있습니다.

"모든 도구의 가장 중요한 측면이 사용자에게 미치는 영향"이라고 Dykstra가 말하지 않았습니까?


1

아마도 인간이 숫자인지 식별자인지 쉽게 알 수 있기 때문일 것입니다. 전통 때문입니다. 숫자로 시작할 수있는 식별자가 어휘 스캔을 복잡하게 만드는 것은 아닙니다.

모든 언어에서 숫자로 시작하는 금지 된 식별자가있는 것은 아닙니다. Forth에서는 숫자 일 수 있으며 작은 정수는 일반적으로 Forth 단어 (필수적으로 식별자)로 정의되었습니다. "2"를 숫자로 인식하는 것보다 스택에 2를 푸시하는 루틴으로 "2"를 읽는 것이 더 빠르기 때문에 (프로그래머 또는 디스크 블록의 입력을 처리 할 때 Forth 시스템은 입력을 공백에 따라 분할합니다. 사전에서 토큰을 찾아 정의 된 단어인지 확인하려고 시도했습니다. 그렇지 않으면 숫자로 변환하려고 시도하지 않으면 오류를 표시합니다.)


문제는 Forth가 실제로 매우 복잡한 파서를 가지고 있지 않다는 것입니다. 실제로, 식별자가 공백의 두 세트 사이에 있는지 여부 만 중요합니다.
Jason Baker

1

기호 이름이 숫자로 시작되도록 허용했다고 가정하십시오. 이제 변수 이름을 12345foobar로 지정한다고 가정하십시오. 이것을 12345와 어떻게 차별화 하시겠습니까? 정규식으로하는 것은 실제로 어렵지 않습니다. 문제는 실제로 성능 중 하나입니다. 나는 이것이 왜 이것이 상세하게 설명 할 수는 없지만, 12345foobar와 12345를 구별하려면 역 추적이 필요하다는 사실로 본질적으로 요약됩니다. 이로 인해 정규 표현식이 결정적이지 않습니다.

여기에 대한 더 나은 설명이 있습니다 .


1
어떻게 변수라는 수 있도록 정규 표현식을 설계하는 것 ifq또는 doublez하지만 ifdouble? 식별자를 숫자로 시작할 수있게하는 근본적인 문제는 완전히 영숫자로 구성된 16 진 리터럴 및 부동 소수점 숫자의 기존 형식이 있다는 것입니다 (언어는 0x1234 대신 $ 1234 또는 h'1234와 같은 것을 사용하며 다음과 같은 숫자가 필요함). 1E23은 기간을 포함하여 해당 문제를 피할 수 있습니다). C를 정규 표현식 파싱하려는 시도는 이미와 같은 것들에 의해 넘어 질 수 있습니다 0x12E+5.
supercat

1

컴파일러가 number 대신 메모리 위치에서 ASCII를 사용하여 변수를 쉽게 식별 할 수 있습니다.


1

컴파일러에는 다음과 같은 7 단계가 있습니다.

  1. 어휘 분석
  2. 구문 분석
  3. 시맨틱 분석
  4. 중급 코드 생성
  5. 코드 최적화
  6. 코드 생성
  7. 기호 표

어휘 분석 단계에서는 코드를 컴파일하는 동안 역 추적을 피할 수 있습니다. Apple과 같은 변수는 어휘 분석 단계에서 문자 'A'문자를 만나면 식별자를 즉시 ​​알 수 있습니다. 그러나 123apple과 같은 변수 인 컴파일러는 'a'에 도달 할 때까지 숫자 또는 식별자를 결정할 수 없으며 변수를 식별하기 위해 어휘 분석 단계로 돌아가려면 역 추적이 필요합니다. 그러나 컴파일러에서는 지원되지 않습니다.

토큰을 구문 분석 할 때 첫 번째 문자 만보고 식별자 또는 리터럴인지 확인한 후 처리를 위해 올바른 함수로 보내야합니다. 이것이 성능 최적화입니다.


0

나는 간단한 대답은 그것이 가능하다는 것입니다. 제한은 언어에 기초합니다. C ++과 다른 많은 언어에서는 언어가 지원하지 않기 때문에 불가능합니다. 그것을 허용하기 위해 규칙에 내장되어 있지 않습니다.

문제는 왕이 왜 체스에서 한 번에 4 칸씩 움직일 수 없는지 묻는 것과 비슷합니다. 그것은 체스에서 불법적 인 행동이기 때문입니다. 다른 게임에서도 확실하게 할 수 있습니다. 규칙에 따라 다릅니다.


C ++은 아직 살아있는 사람들이 최근에 발명 한 것을 제외하고. 우리는 그들이 왜 그들이 한 일을 선택하고 대안을 거부했는지 물을 수 있습니다. 체스에는 동일하지 않습니다.
Steve Jessop

그러나 그것은 내가하고있는 요점이 아닙니다. 변수 이름의 시작 부분에 숫자가없는 이유와 유사하며 가장 간단한 대답은 언어 규칙에 따라 허용되지 않기 때문입니다.
kemiller2002

물론입니다.하지만 질문자가 불완전하다고 생각하지 않습니다. 그는 아마 이미 그 자체로 해결했을 것입니다. 질문 IMO는 "언어의 규칙이 허용하지 않는 이유는 무엇입니까?"입니다. 그는 규칙을 아는 것과 이해하는 것 사이의 격차를 해소하고자합니다.
Steve Jessop

네, 이것에 대해 생각해 보니 당신이 어디로 가고 있는지 깨달았습니다. 당신은 요점이 있습니다. 나는 Occam의 면도기를 약간 자유롭게 적용하고 있었고 숫자가 없기 때문에 변수가 숫자로 시작하지 않는 이유에 대한 실제 대답이 없다고 가정했습니다.
kemiller2002

나는 당신이 틀렸다는 것을 말하는 것이 아닙니다. 때때로 C ++ 표준기구의 결정은 필사자의 이해를 능가하며, "무엇을 결정해야하고 이것을 결정했기 때문에"끝납니다. 그러나 적어도 질문이 있습니다 :-)
Steve Jessop

0

원래 문자열의 의미를 향상 시키거나 동일한 변수 이름을 사용할 수 있도록 문자열에 숫자를 포함 할 수 있지만 변수 이름을 숫자가 아닌 문자열로 기억하기가 더 쉬워서 (더 많은 의미를 부여 할 수 있음) 원래 원래 별도의 그러나 가까운 의미 또는 문맥을 갖는 것으로 지정해야합니다. 예를 들어 loop1, loop2 등은 항상 루프 상태에 있거나 루프 2가 loop1 내의 루프라는 것을 알려줍니다. address 또는 1121298 변수 중 어떤 것을 더 선호합니까 (더 의미가 있습니까)? 어느 것이 더 기억하기 쉬운가? 그러나 언어가 텍스트 또는 숫자 (예 : $ in $ address)뿐만 아니라 다른 것을 사용하는 경우 컴파일러가 다음에 오는 것이 변수로 취급된다는 것을 알려주는 것과 실제로 차이를 두지 않아야합니다 ( 이 경우).


0

변수는 컴파일러에 의해 컴파일 시간에도 값으로 간주 될 수 있으므로 값이 반복해서 값을 호출 할 수 있습니다.


0

코드 조각을 컴파일하는 동안 어휘 분석 단계에서 역 추적을 피할 수 있습니다 . 애플과 같은 변수; , 어휘 분석 단계에서 문자 'A'문자를 만나면 컴파일러는 식별자를 즉시 ​​알 수 있습니다. 그러나 123apple과 같은 변수; 컴파일러는 'a'가 될 때까지 숫자 또는 식별자를 결정할 수 없으며 어휘 분석 단계에서 변수인지 식별하기 위해 역 추적이 필요합니다. 그러나 컴파일러에서는 지원되지 않습니다.

참고


0

variable을 선언 할 때 아무런 문제가 없지만 다음과 같이 다른 곳에서 해당 변수를 사용하려고하면 모호성이 있습니다.

let 1 = "Hello world!" 인쇄 (1) 인쇄 (1)

print는 모든 유형의 변수를 허용하는 일반적인 방법입니다. 따라서 컴파일러는 어떤 상황에서 (1) 정수 값의 1 또는 문자열 값을 저장하는 것을 참조하지 않습니다. 이 상황에서 컴파일러가 더 나은 것을 정의하는 것이 더 좋을 수도 있지만이 모호한 것을 사용하려고 할 때 오류를 수정 하고이 모호성을 제거하는 방법에 대한 수정 기능을 사용하여 오류를 가져옵니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.