Domanda

Consider the following code

#include <stdio.h>
#include <string.h>

main()
{
   const int a = 2;
   long p = (long)&a;
   int *c = (int *)p;
   *c =3;
   printf("%d", a);
}

This code can change the value to a in C but not in C++. I understand that C++ is applying optimization and replacing instances of a with 2. So was this a bug fix in C++ or was the bug fixed by chance due to optimization?

È stato utile?

Soluzione

It's undefined behavior to modify a const value no matter directly or indirectly. This may compile in C and may even run without problem on your machine, but it's still undefined behavior.

The difference between C and C++ on this is: with const int a = 2, C++ treats a as a constant expression, for instance, you can use a as array dimension:

int n[a];  //fine in C++

But in C, a is not a constant expression, with the same code:

int n[a];  //VLA in C99

Here n is not a fixed-sized array, but a variable length array.

Altri suggerimenti

This is not a C vs C++ issue. By modifying a const value (as well as by double-casting a pointer via a long), you enter the realm of undefined behaviour in both languages. Therefore the difference is simply a matter of how the undefined behaviour chooses to manifest itself.

You are casting away the constness out of &a and modifying the pointed value, which is undefined behavior both in C and in C++ (the trip through long just adds some more gratuitous UB). In C++ your compiler happens to optimize more aggressively the constant, but the point of the situation is unchanged.

Your code generates undefined behavior on C++ since you're accessing memory you shouldn't

include <stdio.h>
#include <string.h>

void main()
{
   const int a = 2;
   printf("%x != %x !!", sizeof(long), sizeof(void*)); // on a x64 system 4 != 8
   long p = (long)&a;
   int *c = (int *)p;
   *c =3;
   printf("%d", a);
}

and even if it works on a 32 bit system modifying const memory by casting away the constness is undefined behavior in both languages.

Following is the assembly code generated by g++. The compiler statically use "$2" instead of "a", but in case of gcc it doesn't perform any static optimization. I guess there shouldn't be any undefined behaviour.

    .Ltext0:
                    .section    .rodata

                .LC0:
0000 256400         .string "%d"
                    .text
                    .globl  main
                main:

                .LFB0:

                    .cfi_startproc
                    .cfi_personality 0x3,__gxx_personality_v0
                    .cfi_lsda 0x3,.LLSDA0
0000 55             pushq   %rbp
                    .cfi_def_cfa_offset 16
                    .cfi_offset 6, -16
0001 4889E5         movq    %rsp, %rbp
                    .cfi_def_cfa_register 6
0004 4883EC20       subq    $32, %rsp

                .LBB2:

0008 C745EC02       movl    $2, -20(%rbp)
     000000

000f 488D45EC       leaq    -20(%rbp), %rax
0013 488945F0       movq    %rax, -16(%rbp)

0017 488B45F0       movq    -16(%rbp), %rax
001b 488945F8       movq    %rax, -8(%rbp)

001f 488B45F8       movq    -8(%rbp), %rax
0023 C7000300       movl    $3, (%rax)
     0000

0029 488B45F8       movq    -8(%rbp), %rax
002d 8B00           movl    (%rax), %eax
002f 89C6           movl    %eax, %esi
0031 BF000000       movl    $.LC0, %edi
     00
0036 B8000000       movl    $0, %eax
     00

                .LEHB0:

003b E8000000       call    printf
     00

0040 BE020000       movl    $2, %esi
     00
0045 BF000000       movl    $.LC0, %edi
     00
004a B8000000       movl    $0, %eax
     00
004f E8000000       call    printf
     00

                .LEHE0:

0054 B8000000       movl    $0, %eax
     00
0059 EB08           jmp .L5

                .L4:

005b 4889C7         movq    %rax, %rdi

                .LEHB1:

005e E8000000       call    _Unwind_Resume
     00

                .LEHE1:

                .L5:

                .LBE2:

0063 C9             leave
                    .cfi_def_cfa 7, 8
0064 C3             ret
                    .cfi_endproc

                .LFE0:

                    .globl  __gxx_personality_v0
                    .section    .gcc_except_table,"a",@progbits

                .LLSDA0:

0000 FF             .byte   0xff
0001 FF             .byte   0xff
0002 01             .byte   0x1
0003 08             .uleb128 .LLSDACSE0-.LLSDACSB0

                .LLSDACSB0:

0004 3B             .uleb128 .LEHB0-.LFB0
0005 19             .uleb128 .LEHE0-.LEHB0
0006 5B             .uleb128 .L4-.LFB0
0007 00             .uleb128 0
0008 5E             .uleb128 .LEHB1-.LFB0
0009 05             .uleb128 .LEHE1-.LEHB1
000a 00             .uleb128 0
000b 00             .uleb128 0

                .LLSDACSE0:

                    .text

                .Letext0:
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top