IT이야기

C와 C++ 양쪽에서 유효한 코드가 각 언어로 컴파일되었을 때 다른 동작을 발생시킬 수 있습니까?

cyworld 2022. 7. 23. 10:05
반응형

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++에서 유효한 다음 값은 (대부분) 다른 값이 됩니다.iC 및 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++ 。0C의 경우:

#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);
...

하나sizeofexpressions. 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가지 예가 있습니다.

  1. @Adam Rosenfield가 언급한 바와 같이 size of('a');

  2. //「 」 「 」 、 「 」 。

    int f(int a, int b)
    {
        return a //* blah */ b
            ;
    }
    
  3. 구조물 등예시와 같이 아웃 스코프에 있는 것을 숨깁니다.

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++ 컴파일러를 하여 4C 、 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 arrayC의 .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

반응형