C와 C++ 양쪽에서 유효한 코드가 각 언어로 컴파일되었을 때 다른 동작을 발생시킬 수 있습니까?
C와 C++에는 많은 차이가 있으며 모든 유효한 C 코드가 유효한 C++ 코드는 아닙니다.
('유효'란 구현 고유의/정의되지 않은 등의 동작이 정의된 표준 코드를 의미합니다.)
C와 C++ 양쪽에서 유효한 코드 조각이 각 언어의 표준 컴파일러를 사용하여 컴파일 했을 때 다른 동작을 발생시키는 시나리오가 있습니까?
합리적이고 유용한 비교(질문에서 명백한 허점을 찾으려는 것이 아니라 실제로 유용한 것을 배우려는 것입니다)를 하기 위해 다음과 같이 가정합니다.
- 프리프로세서와 관련된 것은 없습니다(즉, Hacks of the pre-processor )
#ifdef __cplusplus
, pragmas 등) - 구현에서 정의된 모든 것은 두 언어 모두 동일합니다(숫자 제한 등).
- 각 표준의 최신 버전(예: C++98 및 C90 이후)을 비교하고 있습니다.
버전이 중요한 경우, 각각의 버전이 다른 동작을 발생시키는지 알려주십시오.
C++와C90, 구현 정의되지 않은 다른 동작을 얻을 수 있는 방법이 적어도 하나 있습니다.C90에는 한 줄의 코멘트가 없습니다.조금만 주의하면 C90과 C++에서 완전히 다른 결과를 가진 식을 만들 수 있습니다.
int a = 10 //* comment */ 2
+ 3;
C++의 경우,//
줄의 끝에 코멘트가 있기 때문에, 이것은 다음과 같이 동작합니다.
int a = 10 + 3;
C90에는 한 줄의 코멘트가 없기 때문에/* comment */
댓글입니다.첫 번째/
및 그2
는 모두 초기화의 일부이기 때문에 다음과 같은 결과가 됩니다.
int a = 10 / 2 + 3;
따라서 올바른 C++ 컴파일러는 13이지만 완전히 올바른 C90 컴파일러 8이 됩니다.물론 여기서 임의의 숫자를 골랐을 뿐입니다.다른 숫자도 사용할 수 있습니다.
C와 C++에서 유효한 다음 값은 (대부분) 다른 값이 됩니다.i
C 및 C++의 경우:
int i = sizeof('a');
차이에 대한 설명은 C/C++의 문자 크기('a')를 참조하십시오.
이 기사의 또 다른 내용:
#include <stdio.h>
int sz = 80;
int main(void)
{
struct sz { char c; };
int val = sizeof(sz); // sizeof(int) in C,
// sizeof(struct sz) in C++
printf("%d\n", val);
return 0;
}
다음으로 C와 C++의 함수 호출과 객체 선언의 차이 및 C90이 선언되지 않은 함수의 호출을 허용하는 예를 나타냅니다.
#include <stdio.h>
struct f { int x; };
int main() {
f();
}
int f() {
return printf("hello");
}
에서는, 일시적인 C++ 의 경우, 「C++」, 「C++」, 「C+」, 「C+」가 .f
및에서는 C90으로 됩니다.hello
함수를 선언하지 않아도 호출할 수 있기 때문입니다.
혹시 이름이 궁금하실까 봐f
번 오브젝트를 만들려면 C++로, C++로, C++로 합니다.struct f
할 수 있습니다.struct
기능을 원하신다면요.
대 CC90 † C++11)int
★★double
#include <stdio.h>
int main()
{
auto j = 1.5;
printf("%d", (int)sizeof(j));
return 0;
}
의 경우auto
로컬 변수를 의미합니다.C90에서는 변수나 함수 유형을 생략해도 됩니다.로는 「」입니다.int
. C++ C++ 우우 。auto
완전히 다른 것을 의미하며, 이는 컴파일러가 변수를 초기화하는 데 사용된 값에서 변수의 유형을 추론하도록 지시합니다.
아직 언급되지 않은 또 다른 예는 프리프로세서의 차이입니다.
#include <stdio.h>
int main()
{
#if true
printf("true!\n");
#else
printf("false!\n");
#endif
return 0;
}
그러면 C에서는 "false"가, C++에서는 "true"가 출력됩니다.C에서는 정의되지 않은 매크로가 모두 0으로 평가됩니다.C++에서는 1개의 예외가 있습니다. "true" 평가는 1입니다.
C++11 기준:
a. 콤마 연산자는 C에서 lvalue-to-rvalue 변환을 수행하지만 C++는 수행하지 않습니다.
char arr[100];
int s = sizeof(0, arr); // The comma operator is used.
에서는 이 식, 에서는 C++가 .sizeof(char*)
.
b. C++에서 열거자의 유형은 열거형입니다.C에서 열거자의 유형은 int입니다.
enum E { a, b, c };
sizeof(a) == sizeof(int); // In C
sizeof(a) == sizeof(E); // In C++
, ,,sizeof(int)
하지 않을 수 sizeof(E)
.
c. C++에서는 빈 매개 변수 목록으로 선언된 함수는 인수를 받지 않습니다.C 빈 매개 변수 목록은 함수 매개 변수의 수와 유형을 알 수 없음을 의미합니다.
int f(); // int f(void) in C++
// int f(*unknown*) in C
#include <stdio.h>
int main(void)
{
printf("%d\n", (int)sizeof('a'));
return 0;
}
C의 값, C의 값, C의 값, C의 값, C의 값, C의 값, C의 값, C의 값, C의 값 등이든 출력합니다.sizeof(int)
는 현재 .일반적으로 이 은 '이러한 시스템'입니다.일반적으로는4
현재 일반적으로 사용되는 대부분의 시스템에서 사용됩니다.
C++에서는 1로 인쇄해야 합니다.
은 인쇄합니다.1
및 C++ 。0
C의 경우:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int d = (int)(abs(0.6) + 0.5);
printf("%d", d);
return 0;
}
은, 「 」가 있기 에 발생합니다.double abs(double)
, 즉 C++의 과부하abs(0.6)
0.6
에서는 C가 반환됩니다.0
"Double-to-int"를 호출하기 에 암묵적인 입니다.int abs(int)
C를 fabs
double
.
C 컴파일러에 의존하는 오래된 밤, C++ 엔드 오브 라인 코멘트를 인식하지 않음...
...
int a = 4 //* */ 2
+2;
printf("%i\n",a);
...
하나sizeof
expressions. trap: " " 입니다.
#include <stdio.h>
int main() {
printf("%d\n", (int)sizeof !0);
}
은 와다 to to에 한다.sizeof(int)
이 int
,, 보 C++ 1 1 ( 、 입 C++ 1 1 ( 。을 사용법
C++ 규격에 기재되어 있는 다른 것:
#include <stdio.h>
int x[1];
int main(void) {
struct x { int a[2]; };
/* size of the array in C */
/* size of the struct in C++ */
printf("%d\n", (int)sizeof(x));
}
C++ Programming Language (제3판)에는 다음 3가지 예가 있습니다.
@Adam Rosenfield가 언급한 바와 같이 size of('a');
//
「 」 「 」 、 「 」 。int f(int a, int b) { return a //* blah */ b ; }
구조물 등예시와 같이 아웃 스코프에 있는 것을 숨깁니다.
C 의 인라인 함수는 디폴트로 외부 스코프가 됩니다만, C++ 의 인라인 함수는 외부 스코프가 되지 않습니다.
다음의 2개의 파일을 함께 컴파일 하면, GNU C 의 경우는 「I am inline」이 인쇄되지만, C++ 의 경우는 인쇄되지 않습니다.
파일 1
#include <stdio.h>
struct fun{};
int main()
{
fun(); // In C, this calls the inline function from file 2 where as in C++
// this would create a variable of struct fun
return 0;
}
파일 2
#include <stdio.h>
inline void fun(void)
{
printf("I am inline\n");
}
는 암묵적으로 의 ,, C++를 취급합니다.const
로 지정합니다.static
으로 「」라고 선언되어 .extern
「」가 되는 , C는 「」입니다extern
을 사용하다
#include <stdio.h>
struct A {
double a[32];
};
int main() {
struct B {
struct A {
short a, b;
} a;
};
printf("%d\n", sizeof(struct A));
return 0;
}
은 인쇄합니다.128
)32 * sizeof(double)
및 C++ 컴파일러를 하여 4
C 、 C 、 C 、 C 、 C 、 C c c c c c c c c c c 。
이는 C가 스코프 분해능의 개념을 가지고 있지 않기 때문입니다.다른 구조물에 포함된 C구조물은 외부구조물의 범위에 포함된다.
int main(void) {
const int dim = 5;
int array[dim];
}
이것은, C++ 및 C99, C11, 및 C17(C11, C17 에서는 옵션이지만)에서는 유효하지만, C89 에서는 유효하지 않다는 점에서 특이합니다.
에서는 가변 배열이 생성됩니다.이 배열은 유형이 배열에 .C99+에서는 C99+를 사용합니다.이 어레이는 컴파일 타임 타입이 아닌 런타임 타입을 가지고 있기 때문에 일반 어레이에 비해 독자적인 특징이 있습니다.sizeof array
C의 .C++로 하다
여기서 이니셜라이저를 추가하려고 하면:
int main(void) {
const int dim = 5;
int array[dim] = {0};
}
는 유효한 C++이지만 C는 아닙니다.변수 길이 배열에는 이니셜라이저를 사용할 수 없기 때문입니다.
C와 C++ 글로벌 네임스페이스의 차이를 잊지 마십시오.foo.cpp가 있다고 가정합니다.
#include <cstdio>
void foo(int r)
{
printf("I am C++\n");
}
및 foo2.c
#include <stdio.h>
void foo(int r)
{
printf("I am C\n");
}
다음으로 main.c와 main.cpp가 모두 다음과 같이 되어 있다고 가정합니다.
extern void foo(int);
int main(void)
{
foo(1);
return 0;
}
C++로 컴파일되면 C++ 글로벌네임스페이스의 기호를 사용합니다.C에서는 C를 사용합니다.
$ diff main.cpp main.c
$ gcc -o test main.cpp foo.cpp foo2.c
$ ./test
I am C++
$ gcc -o test main.c foo.cpp foo2.c
$ ./test
I am C
struct abort
{
int x;
};
int main()
{
abort();
return 0;
}
종료 코드 0(C++) 또는 3(C)을 반환한다.
이 트릭은 좀 더 재미있는 일을 할 수 있을 것 같은데, C가 좋아할 만한 컨스트럭터를 만들 수 있는 좋은 방법이 생각나지 않았습니다.카피 컨스트럭터와 마찬가지로 지루한 예를 들어보려고 했습니다.그것은, 비록 휴대할 수 없는 방식이지만, 논쟁을 통과시킬 수 있는 것입니다.
struct exit
{
int x;
};
int main()
{
struct exit code;
code.x=1;
exit(code);
return 0;
}
그러나 VC++ 2005는 "Exit 코드"가 어떻게 재정의되었는지에 대해 불만을 표시하며 C++ 모드에서 컴파일을 거부했습니다.(갑자기 프로그래밍 방법을 잊어버린 경우가 아니라면 컴파일러 버그라고 생각합니다.)그러나 C로 컴파일된 경우 프로세스 종료 코드 1로 종료되었습니다.
이것은 C와 C++의 l값과 rvalue에 관한 것입니다.
C의 프리 인크리먼트, post-increment, post-increment, lvalue, rvalue, rvalue. 수 입니다.=
두 C in이 C: in에에이 、 C : 두 、 C 서서 。
int a = 5;
a++ = 2; /* error: lvalue required as left operand of assignment */
++a = 2; /* error: lvalue required as left operand of assignment */
그러나 C++에서는 사전 증분 연산자는 l 값을 반환하고 사후 증분 연산자는 r 값을 반환합니다.즉, pre-increment 연산자가 있는 식을 pre-increment 연산자의 왼쪽에 배치할 수 있습니다.=
★★★★★★★★★★★★★★★★!
int a = 5;
a++ = 2; // error: lvalue required as left operand of assignment
++a = 2; // No error: a gets assigned to 2!
왜 그럴까?Post-Increment는 변수를 증분하고 증분 발생 전 상태로 변수를 반환합니다.이것은 실제로는 r값일 뿐입니다.변수 a의 이전 값이 레지스터에 임시로 복사되고 a가 증분됩니다.단, a의 이전 값은 식에 의해 반환됩니다.이것은 r값입니다.변수의 현재 내용을 더 이상 나타내지 않습니다.
사전 인크리먼트는 먼저 변수를 인크리먼트한 후 인크리먼트가 발생한 후의 변수를 반환합니다.이 경우 변수의 오래된 값을 임시 레지스터에 저장할 필요가 없습니다.변수 값이 증가된 후 새 값을 가져옵니다.따라서 프리 인크리먼트는 l값을 반환하고 변수 a 자체를 반환합니다.이 lvalue를 다른 것에 할당할 수 있습니다.이것은 다음 문과 같습니다.이것은 lvalue를 rvalue로 암묵적으로 변환한 것입니다.
int x = a;
int x = ++a;
pre-increment는 l값을 반환하기 때문에 그 값을 할당할 수도 있습니다.다음 두 개의 문장은 동일합니다.두 번째 할당에서는 첫 번째 a가 증분된 후 새 값이 2로 덮어씁니다.
int a;
a = 2;
++a = 2; // Valid in C++.
빈 구조의 크기는 C에서 0, C++에서 1입니다.
#include <stdio.h>
typedef struct {} Foo;
int main()
{
printf("%zd\n", sizeof(Foo));
return 0;
}
언급URL : https://stackoverflow.com/questions/12887700/can-code-that-is-valid-in-both-c-and-c-produce-different-behavior-when-compile
'IT이야기' 카테고리의 다른 글
v-model에서 입력 유형="file"을 지원하지 않습니다. (0) | 2022.07.23 |
---|---|
vue.js에서 개체를 포함하는 데이터 어레이를 표시하는 방법 (0) | 2022.07.23 |
vuejs에서 개체가 확장 가능하지 않음 오류입니다. (0) | 2022.07.23 |
1개의 클래스 vue.js 2에 2개의 조건을 추가하려면 어떻게 해야 하나요? (0) | 2022.07.23 |
Java에서 사용되지 않는 메서드 또는 클래스를 사용하는 것이 잘못되었습니까? (0) | 2022.07.23 |