Возможность изменить значение const в C, но не в C ++

0

Рассмотрим следующий код

#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++ или ошибка была исправлена случайно из-за оптимизации?

  • 4
    В C ++ (и, скорее всего, в C тоже) это неопределенное поведение. Вы могли бы на самом деле преуспеть в изменении значения объекта const . Поэтому все, что вы видите, можно считать «случайным» (конечно, просмотр сборки покажет вам, что происходит с вашей конкретной платформой и опциями компилятора.)
  • 0
    возможный дубликат переменной Const изменен с указателем в C
Теги:
optimization
const

5 ответов

6
Лучший ответ

Это неопределенное поведение для изменения значения 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 не является массивом фиксированного размера, а массивом переменной длины.

6

Это не проблема C vs C++. const значение const (а также двойным нажатием указателя через long), вы вводите область неопределенного поведения на обоих языках. Поэтому различие - это просто вопрос того, как неопределенное поведение выбирает проявить себя.

  • 0
    Поскольку поведение не определено, можем ли мы ожидать разные результаты, если мы скомпилируем и запустим одну и ту же программу несколько раз?
  • 0
    @ user1173339: Это также будет верным проявлением неопределенного поведения. Конечно, вы не можете ожидать, что это произойдет: всегда печатать слово « bananas было бы таким же допустимым проявлением, как и любое другое поведение (сбой, твит от вашего имени, все вышеперечисленное, вообще ничего и т. Д.) ,
Показать ещё 2 комментария
1

Вы отбрасываете константу из &a и изменяете заостренное значение, что является неопределенным поведением как на C, так и в C++ (поездка по long просто добавляет еще более бесплатный UB). В C++ ваш компилятор, наоборот, более агрессивно оптимизирует константу, но ситуация не меняется.

0

Ниже приведен код сборки, сгенерированный 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:
  • 1
    Плохое предположение. Неопределенное поведение зависит не от того, что делает конкретный компилятор, а от того, какое поведение можно ожидать от любого компилятора.
0

Ваш код генерирует неопределенное поведение на 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, отбрасывая константу, это неопределенное поведение на обоих языках.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню