Рассмотрим следующий код
#include <stdio.h>
#include <string.h>
main()
{
const int a = 2;
long p = (long)&a;
int *c = (int *)p;
*c =3;
printf("%d", a);
}
Этот код может изменить значение на a в C, но не в C++. Я понимаю, что C++ применяет оптимизацию и заменяет экземпляры a
на 2
. Так было ли это исправление ошибок в C++ или ошибка была исправлена случайно из-за оптимизации?
Это неопределенное поведение для изменения значения const
независимо от того, прямо или косвенно. Это может быть скомпилировано на C и может даже работать без проблем на вашем компьютере, но это все еще неопределенное поведение.
Разница между С и C++ на это: с const int a = 2
, C++ рассматривает как постоянное выражение, например, вы можете использовать как измерение массива: a
a
int n[a]; //fine in C++
Но в C, a
не является постоянным выражением, с тем же кодом:
int n[a]; //VLA in C99
Здесь n
не является массивом фиксированного размера, а массивом переменной длины.
Это не проблема C vs C++. const
значение const
(а также двойным нажатием указателя через long
), вы вводите область неопределенного поведения на обоих языках. Поэтому различие - это просто вопрос того, как неопределенное поведение выбирает проявить себя.
bananas
было бы таким же допустимым проявлением, как и любое другое поведение (сбой, твит от вашего имени, все вышеперечисленное, вообще ничего и т. Д.) ,
Вы отбрасываете константу из &a
и изменяете заостренное значение, что является неопределенным поведением как на C, так и в C++ (поездка по long
просто добавляет еще более бесплатный UB). В C++ ваш компилятор, наоборот, более агрессивно оптимизирует константу, но ситуация не меняется.
Ниже приведен код сборки, сгенерированный g++. Компилятор статически использует "$ 2" вместо "a", но в случае gcc он не выполняет статической оптимизации. Я думаю, не должно быть никакого неопределенного поведения.
.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:
Ваш код генерирует неопределенное поведение на C++, так как вы обращаетесь к памяти, вы не должны
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);
}
и даже если он работает на 32-битной системе, изменяющей память const
, отбрасывая константу, это неопределенное поведение на обоих языках.
const
. Поэтому все, что вы видите, можно считать «случайным» (конечно, просмотр сборки покажет вам, что происходит с вашей конкретной платформой и опциями компилятора.)