C와 C ++ 모두에서 유효한 코드가 각 언어로 컴파일 될 때 다른 동작을 생성 할 수 있습니까?
C와 C ++에는 많은 차이가 있으며 모든 유효한 C 코드가 유효한 C ++ 코드는 아닙니다.
( "유효"란 정의 된 동작이있는 표준 코드를 의미합니다. 즉, 구현 특정 / 정의되지 않음 / 등이 아닙니다.)
C와 C ++ 모두에서 유효한 코드 조각이 각 언어의 표준 컴파일러로 컴파일 될 때 다른 동작을 생성하는 시나리오가 있습니까?
합리적이고 유용한 비교를하기 위해 (질문에서 명백한 허점을 찾으려하지 않고 실질적으로 유용한 것을 배우려고합니다) 다음과 같이 가정 해 봅시다.
- 전 처리기 관련 없음 (즉
#ifdef __cplusplus
,, pragma 등의 해킹이 없음을 의미 함 ) - 구현 정의 된 모든 것은 두 언어에서 동일합니다 (예 : 숫자 제한 등).
- 각 표준의 합리적으로 최신 버전 (예 : C ++ 98 및 C90 이상)을 비교
하고 있습니다. 버전이 중요하다면 각 버전이 다른 동작을 생성하는지 언급하십시오.
C 및 C ++에서 유효한 다음은 C 및 C ++에서 다른 값을 생성 할 가능성이 높습니다 i
.
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 ++에서는 임시 f
가 생성되고 소멸 되기 때문에 아무것도 인쇄하지 않지만 C90에서는 hello
선언하지 않고도 함수를 호출 할 수 있기 때문에 인쇄 합니다.
f
두 번 사용되는 이름 에 대해 궁금한 경우 C 및 C ++ 표준이이를 명시 적으로 허용 struct f
하고 구조를 원하면 명확하게 말해야하는 객체를 만들고 struct
함수를 원하면 그만 두어야 합니다.
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을 제공합니다. 물론 여기에서 임의의 숫자를 선택했습니다. 적합하다고 생각되는 다른 숫자를 사용할 수 있습니다.
C90 대 C ++ 11 ( int
대 double
) :
#include <stdio.h>
int main()
{
auto j = 1.5;
printf("%d", (int)sizeof(j));
return 0;
}
C에서 auto
지역 변수를 의미합니다. C90에서는 변수 또는 함수 유형을 생략해도됩니다. 기본값은 int
입니다. C ++ 11에서는 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 표준에 따라 :
ㅏ. 쉼표 연산자는 C에서 lvalue에서 rvalue로 변환을 수행하지만 C ++에서는 수행하지 않습니다.
char arr[100];
int s = sizeof(0, arr); // The comma operator is used.
C ++에서이 표현식의 값은 100이고 C에서는 sizeof(char*)
.
비. 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 ++에서 빈 params 목록으로 선언 된 함수는 인수를 사용하지 않습니다. C에서 빈 매개 변수 목록은 함수 매개 변수의 수와 유형을 알 수 없음을 의미합니다.
int f(); // int f(void) in C++
// int f(*unknown*) in C
이 프로그램 1
은 C ++ 및 C로 인쇄합니다 0
.
#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 ++에 과부하 가 있기 때문에 발생하므로 C 에서는를 호출하기 전에 암시 적 double-int 변환으로 인해 abs(0.6)
반환 0.6
하는 동안 반환 됩니다. C에서는를 사용 하여 .0
int abs(int)
fabs
double
또 다른 sizeof
함정 : 부울 표현식.
#include <stdio.h>
int main() {
printf("%d\n", (int)sizeof !0);
}
sizeof(int)
표현식이 유형이므로 C에서 와 동일 int
하지만 일반적으로 C ++에서는 1입니다 (필수는 아님). 실제로 그들은 거의 항상 다릅니다.
#include <stdio.h>
int main(void)
{
printf("%d\n", (int)sizeof('a'));
return 0;
}
C에서 이것은 일반적으로 오늘날 일반적으로 사용되는 대부분의 시스템에서 sizeof(int)
현재 시스템 의 값이 무엇이든 인쇄 4
합니다.
C ++에서는 1을 인쇄해야합니다.
C ++ 프로그래밍 언어 (3 판) 는 세 가지 예를 제공합니다.
@Adam Rosenfield가 언급했듯이 sizeof ( 'a');
//
숨겨진 코드를 만드는 데 사용되는 주석 :int f(int a, int b) { return a //* blah */ b ; }
구조 등은 귀하의 예에서와 같이 범위 밖에서 물건을 숨 깁니다.
C ++ 라인 끝 주석을 인식하지 못하는 C 컴파일러에 의존하는 오래된 밤 ...
...
int a = 4 //* */ 2
+2;
printf("%i\n",a);
...
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의 인라인 함수는 기본적으로 C ++의 함수가 아닌 외부 범위로 설정됩니다.
다음 두 파일을 함께 컴파일하면 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 ++ 는 기본값 인 C와 달리 명시 적으로 선언되지 않는 한 const
전역을 암시 적으로 처리합니다 .static
extern
extern
struct abort
{
int x;
};
int main()
{
abort();
return 0;
}
C ++에서는 0, C에서는 3의 종료 코드를 반환합니다.
This trick could probably be used to do something more interesting, but I couldn't think of a good way of creating a constructor that would be palatable to C. I tried making a similarly boring example with the copy constructor, that would let an argument be passed, albeit in a rather non-portable fashion:
struct exit
{
int x;
};
int main()
{
struct exit code;
code.x=1;
exit(code);
return 0;
}
VC++ 2005 refused to compile that in C++ mode, though, complaining about how "exit code" was redefined. (I think this is a compiler bug, unless I've suddenly forgotten how to program.) It exited with a process exit code of 1 when compiled as C though.
#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;
}
This program prints 128
(32 * sizeof(double)
) when compiled using a C++ compiler and 4
when compiled using a C compiler.
This is because C does not have the notion of scope resolution. In C structures contained in other structures get put into the scope of the outer structure.
Don't forget the distinction between the C and C++ global namespaces. Suppose you have a foo.cpp
#include <cstdio>
void foo(int r)
{
printf("I am C++\n");
}
and a foo2.c
#include <stdio.h>
void foo(int r)
{
printf("I am C\n");
}
Now suppose you have a main.c and main.cpp which both look like this:
extern void foo(int);
int main(void)
{
foo(1);
return 0;
}
When compiled as C++, it will use the symbol in the C++ global namespace; in C it will use the C one:
$ 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
int main(void) {
const int dim = 5;
int array[dim];
}
This is rather peculiar in that it is valid in C++ and in C99, C11, and C17 (though optional in C11, C17); but not valid in C89.
In C99+ it creates a variable-length array, which has its own peculiarities over normal arrays, as it has a runtime type instead of compile-time type, and sizeof array
is not an integer constant expression in C. In C++ the type is wholly static.
If you try to add an initializer here:
int main(void) {
const int dim = 5;
int array[dim] = {0};
}
is valid C++ but not C, because variable-length arrays cannot have an initializer.
This concerns lvalues and rvalues in C and C++.
In the C programming language, both the pre-increment and the post-increment operators return rvalues, not lvalues. This means that they cannot be on the left side of the =
assignment operator. Both these statements will give a compiler error in C:
int a = 5;
a++ = 2; /* error: lvalue required as left operand of assignment */
++a = 2; /* error: lvalue required as left operand of assignment */
In C++ however, the pre-increment operator returns an lvalue, while the post-increment operator returns an rvalue. It means that an expression with the pre-increment operator can be placed on the left side of the =
assignment operator!
int a = 5;
a++ = 2; // error: lvalue required as left operand of assignment
++a = 2; // No error: a gets assigned to 2!
Now why is this so? The post-increment increments the variable, and it returns the variable as it was before the increment happened. This is actually just an rvalue. The former value of the variable a is copied into a register as a temporary, and then a is incremented. But the former value of a is returned by the expression, it is an rvalue. It no longer represents the current content of the variable.
The pre-increment first increments the variable, and then it returns the variable as it became after the increment happened. In this case, we do not need to store the old value of the variable into a temporary register. We just retrieve the new value of the variable after it has been incremented. So the pre-increment returns an lvalue, it returns the variable a itself. We can use assign this lvalue to something else, it is like the following statement. This is an implicit conversion of lvalue into rvalue.
int x = a;
int x = ++a;
Since the pre-increment returns an lvalue, we can also assign something to it. The following two statements are identical. In the second assignment, first a is incremented, then its new value is overwritten with 2.
int a;
a = 2;
++a = 2; // Valid in C++.
Empty structures have size 0 in C and 1 in C++:
#include <stdio.h>
typedef struct {} Foo;
int main()
{
printf("%zd\n", sizeof(Foo));
return 0;
}
'IT박스' 카테고리의 다른 글
N 일보다 오래된 파일을 삭제하는 배치 파일 (0) | 2020.10.02 |
---|---|
폴더가없는 경우 새로 만듭니다. (0) | 2020.10.02 |
div에서 요소를 수직으로 정렬하는 방법은 무엇입니까? (0) | 2020.09.30 |
Android 에뮬레이터에 APK 파일을 어떻게 설치합니까? (0) | 2020.09.30 |
모나드는 endofunctor 범주의 모노 이드 일뿐입니다. 무엇이 문제입니까? (0) | 2020.09.30 |