C/С++ меняет значение const
У меня была статья, но я ее потерял. Он показал и описал пару трюков на C/С++, которые должны быть осторожны. Один из них интересовал меня, но теперь, когда я пытаюсь воспроизвести его, я не могу его компилировать.
Понятие состояло в том, что можно случайно изменить значение a const
в C/С++
Это было что-то вроде этого:
const int a = 3; // I promise I won't change a
const int *ptr_to_a = &a; // I still promise I won't change a
int *ptr;
ptr = ptr_to_a;
(*ptr) = 5; // I'm a liar; a is now 5
Я хотел показать это другу, но теперь я пропустил шаг. Кто-нибудь знает, что ему не хватает, чтобы начать компиляцию и работу?
ATM Я получаю недействительное преобразование из 'const int *' в 'int *', но когда я прочитал статью, которую я пробовал, и она отлично работала.
Ответы
Ответ 1
вам нужно отбросить константу:
linux ~ $ cat constTest.c
#include <stdio.h>
void modA( int *x )
{
*x = 7;
}
int main( void )
{
const int a = 3; // I promisse i won't change a
int *ptr;
ptr = (int*)( &a );
printf( "A=%d\n", a );
*ptr = 5; // I'm a liar, a is now 5
printf( "A=%d\n", a );
*((int*)(&a)) = 6;
printf( "A=%d\n", a );
modA( (int*)( &a ));
printf( "A=%d\n", a );
return 0;
}
linux ~ $ gcc constTest.c -o constTest
linux ~ $ ./constTest
A=3
A=5
A=6
A=7
linux ~ $ g++ constTest.c -o constTest
linux ~ $ ./constTest
A=3
A=3
A=3
A=3
также общий ответ не работает в g ++ 4.1.2
linux ~ $ cat constTest2.cpp
#include <iostream>
using namespace std;
int main( void )
{
const int a = 3; // I promisse i won't change a
int *ptr;
ptr = const_cast<int*>( &a );
cout << "A=" << a << endl;
*ptr = 5; // I'm a liar, a is now 5
cout << "A=" << a << endl;
return 0;
}
linux ~ $ g++ constTest2.cpp -o constTest2
linux ~ $ ./constTest2
A=3
A=3
linux ~ $
btw.. это никогда не рекомендуется... Я обнаружил, что g++ не позволяет это произойти.. так что это может быть проблема, с которой вы столкнулись.
Ответ 2
Просто догадаться, но общий вопрос заключается в том, почему нельзя преобразовать int**
в const int**
, который сначала кажется разумным (в конце концов, вы просто добавляете const
, который нормально нормально). Причина в том, что если вы можете это сделать, вы можете случайно изменить объект const
:
const int x = 3;
int *px;
const int **ppx = &px; // ERROR: conversion from 'int**' to 'const int**'
*ppx = &x; // ok, assigning 'const int*' to 'const int*'
*px = 4; // oops, just modified a const object
Это очень неинтуитивный результат, но единственный способ убедиться, что вы не можете изменить объект const
в этом случае (обратите внимание на то, что нет никаких типов) - это сделать строку 3 ошибкой.
Вам разрешено добавлять const
без трансляции на FIRST уровне косвенности:
int * const *ppx = &px; // this is ok
*ppx = &x; // but now this is an error because *ppx is 'const'
В С++ невозможно изменить объект const
без использования определенного типа. Вам нужно будет использовать либо C-стиль, либо стиль С++ const_cast
, чтобы удалить const
-ness. Любая другая попытка сделать это приведет к ошибке компилятора.
Ответ 3
Обратите внимание, что любая попытка отбросить константу составляет undefined по стандарту. Из стандарта 7.1.5.1 стандарта:
За исключением того, что объявлен любой член класса mutable может быть изменен, любой попытка изменить объект const в течение своей жизни приводит к поведению undefined.
И сразу после использования этого примера:
const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object
Короче говоря, вы не можете использовать стандартный С++.
Далее, когда компилятор встречает объявление типа
const int a = 3; // I promisse i won't change a
можно заменить любую "а" на 3 (фактически делая то же самое, что и #define a 3
)
Ответ 4
В тумане времени мы, палео-программисты, использовали FORTRAN. FORTRAN передал все свои параметры по ссылке и не выполнял никаких проверок типов. Это означало, что было довольно легко случайно изменить значение даже постоянной константы. Вы можете передать "3" в SUBROUTINE, и он вернется с изменением, и поэтому каждый раз с того момента, когда ваш код имеет "3", он фактически будет действовать как другое значение. Позвольте мне сказать вам, что это были трудные ошибки, чтобы найти и исправить.
Ответ 5
Вы пробовали это?
ptr = const_cast<int *>(ptr_to_a);
Это должно помочь скомпилировать его, но это не случайно из-за броска.
Ответ 6
В С++, используя Microsoft Visual Studio-2008
const int a = 3; /* I promisse i won't change a */
int * ptr1 = const_cast<int*> (&a);
*ptr1 = 5; /* I'm a liar, a is now 5 . It not okay. */
cout << "a = " << a << "\n"; /* prints 3 */
int arr1[a]; /* arr1 is an array of 3 ints */
int temp = 2;
/* or, const volatile int temp = 2; */
const int b = temp + 1; /* I promisse i won't change b */
int * ptr2 = const_cast<int*> (&b);
*ptr2 = 5; /* I'm a liar, b is now 5 . It okay. */
cout << "b = " << b << "\n"; /* prints 5 */
//int arr2[b]; /* Compilation error */
В C переменная const может быть изменена посредством указателя; однако это поведение undefined. Константная переменная никогда не может использоваться как длина в объявлении массива.
В С++, если константная переменная инициализируется чистым константным выражением, тогда ее значение не может быть изменено с помощью указателя даже после попытки изменения, иначе переменная const может быть изменена через ее указатель.
Чистая интегральная константная переменная может использоваться как длина в объявлении массива, если ее значение больше 0.
Чистое постоянное выражение состоит из следующих операндов.
-
Числовой литерал (постоянный), например. 2, 10.53
-
Символьная константа, определяемая директивой #define
-
Константа перечисления
-
Чистая константная переменная, то есть константная переменная, которая сама инициализируется чистым константным выражением.
-
Неконстантные переменные или изменчивые переменные не допускаются.
Ответ 7
Вероятно, вы хотите использовать const_cast:
int *ptr = const_cast<int*>(ptr_to_a);
Я не уверен на 100%, это будет работать, хотя я немного ржавый на C/С++: -)
Некоторое чтение для const_cast: http://msdn.microsoft.com/en-us/library/bz6at95h(VS.80).aspx
Ответ 8
const int foo = 42;
const int *pfoo = &foo;
const void *t = pfoo;
void *s = &t; // pointer to pointer to int
int **z = (int **)s; // pointer to int
**z = 0;
Ответ 9
В статье, на которую вы смотрели, возможно, говорилось о различии между
const int *pciCantChangeTarget;
const int ci = 37;
pciCantChangeTarget = &ci; // works fine
*pciCantChangeTarget = 3; // compile error
и
int nFirst = 1;
int const *cpiCantChangePointerValue = &nFirst;
int nSecond = 968;
*pciCantChangePointerValue = 402; // works
cpiCantChangePointerValue = &ci; // compile error
Или так я помню... у меня нет ничего, кроме инструментов Java, поэтому не могу проверить:)
Ответ 10
В некоторых из этих ответов указывается, что компилятор может оптимизировать переменную 'a', поскольку она объявлена const
. Если вы действительно хотите изменить значение a
, тогда вам нужно пометить его как volatile
const volatile int a = 3; // I promise i won't change a
int *ptr = (int *)&a;
(*ptr) = 5; // I'm a liar, a is now 5
Конечно, объявление чего-то как const volatile
должно действительно иллюстрировать, насколько это глупо.
Ответ 11
#include<iostream>
int main( void )
{
int i = 3;
const int *pi = &i;
int *pj = (int*)&i;
*pj = 4;
getchar();
return 0;
}
Ответ 12
мы можем изменить значение переменной const следующим кодом:
const int x=5;
printf("\nValue of x=%d",x);
*(int *)&x=7;
printf("\nNew value of x=%d",x);
Ответ 13
Я смотрел, как конвертировать между константами, и я нашел этот http://www.possibility.com/Cpp/const.html, возможно, он может быть кому-то полезен.:)
Ответ 14
Я проверил код ниже и успешно изменяет постоянные переменные-члены.
#include <iostream>
class A
{
private:
int * pc1; // These must stay on the top of the constant member variables.
int * pc2; // Because, they must be initialized first
int * pc3; // in the constructor initialization list.
public:
A() : c1(0), c2(0), c3(0), v1(0), v2(0), v3(0) {}
A(const A & other)
: pc1 (const_cast<int*>(&other.c1)),
pc2 (const_cast<int*>(&other.c2)),
pc3 (const_cast<int*>(&other.c3)),
c1 (*pc1),
c2 (*pc2),
c3 (*pc3),
v1 (other.v1),
v2 (other.v2),
v3 (other.v3)
{
}
A(int c11, int c22, int c33, int v11, int v22, int v33) : c1(c11), c2(c22), c3(c33), v1(v11), v2(v22), v3(v33)
{
}
const A & operator=(const A & Rhs)
{
pc1 = const_cast<int*>(&c1);
pc2 = const_cast<int*>(&c2),
pc3 = const_cast<int*>(&c3),
*pc1 = *const_cast<int*>(&Rhs.c1);
*pc2 = *const_cast<int*>(&Rhs.c2);
*pc3 = *const_cast<int*>(&Rhs.c3);
v1 = Rhs.v1;
v2 = Rhs.v2;
v3 = Rhs.v3;
return *this;
}
const int c1;
const int c2;
const int c3;
int v1;
int v2;
int v3;
};
std::wostream & operator<<(std::wostream & os, const A & a)
{
os << a.c1 << '\t' << a.c2 << '\t' << a.c3 << '\t' << a.v1 << '\t' << a.v2 << '\t' << a.v3 << std::endl;
return os;
}
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
A ObjA(10, 20, 30, 11, 22, 33);
A ObjB(40, 50, 60, 44, 55, 66);
A ObjC(70, 80, 90, 77, 88, 99);
A ObjD(ObjA);
ObjB = ObjC;
std::wcout << ObjA << ObjB << ObjC << ObjD;
system("pause");
return 0;
}
Выход консоли:
10 20 30 11 22 33
70 80 90 77 88 99
70 80 90 77 88 99
10 20 30 11 22 33
Press any key to continue . . .
Здесь гандикап, вы должны определить столько указателей, сколько количества постоянных переменных-членов, которые у вас есть.
Ответ 15
это приведет к сбою во время выполнения. Поскольку int статический. Необработанное исключение. Место записи нарушения доступа 0x00035834.
void main(void)
{
static const int x = 5;
int *p = (int *)x;
*p = 99; //here it will trigger the fault at run time
}
Ответ 16
#include<stdio.h>
#include<stdlib.h>
int main(void) {
const int a = 1; //a is constant
fprintf(stdout,"%d\n",a);//prints 1
int* a_ptr = &a;
*a_ptr = 4;//memory leak in c(value of a changed)
fprintf(stdout,"%d",a);//prints 4
return 0;
}
Ответ 17
Окончательное решение: оно изменит значение переменной const
;
cont int a = 10;
*(int*)&a= 5; // now a prints 5
// works fine.
Ответ 18
Недопустимый шаг: вам не нужен указатель int *. Строка:
const int *ptr_to_a = &a; // I still promiss i won't change a;
на самом деле говорит, что вы не измените ptr_to_a, а не a. Поэтому, если вы изменили свой код так:
const int a = 3; // I promise I won't change a
const int *ptr_to_a = &a; // I promise I won't change ptr_to_a, not a.
(*ptr_to_a) = 5; // a is now 5
a теперь 5. Вы можете изменить сквозной ptr_to_a без предупреждения.
EDIT:
Вышеуказанное неверно. Оказывается, я сбивал с толку подобный трюк с shared_ptr, в котором вы можете получить доступ к необработанному указателю и изменить внутреннее значение данных, не отпуская никаких предупреждений. То есть:
#include <iostream>
#include <boost/shared_ptr.hpp>
int main()
{
const boost::shared_ptr<int>* a = new boost::shared_ptr<int>(new int(3));
*(a->get()) = 5;
std::cout << "A is: " << *(a->get()) << std::endl;
return 0;
}
Произведет 5.