Câu hỏi C / C ++ thay đổi giá trị của một const


Tôi đã có một bài viết, nhưng tôi đã mất nó. Nó cho thấy và mô tả một vài thủ thuật C / C ++ mà mọi người nên cẩn thận. Một trong số họ quan tâm đến tôi nhưng bây giờ tôi đang cố gắng tái tạo nó, tôi không thể đưa nó vào biên dịch được.

Khái niệm là có thể thay đổi do tai nạn giá trị của một const trong C / C ++

Đó là một cái gì đó như thế này:

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

Tôi muốn thể hiện điều này với một người bạn nhưng bây giờ tôi đang bỏ lỡ một bước. Có ai biết những gì còn thiếu để bắt đầu biên dịch và làm việc không?

ATM tôi đang nhận chuyển đổi không hợp lệ từ 'const int *' thành 'int *' nhưng khi tôi đọc bài báo tôi đã thử và nó hoạt động rất tốt.


14
2018-02-24 18:55


gốc


Tôi đã đăng một chương trình hoàn chỉnh và giải thích rằng đó là g ++ đang chặn nó, gcc cho phép hành vi này. - sfossen
Ngay cả khi bạn làm cho nó để biên dịch. nó là hành vi không xác định. Nó có thể làm hỏng máy tính của bạn, làm hỏng chương trình của bạn, hoặc làm cho con quỷ bay ra khỏi mũi của bạn. Hoặc, tất nhiên, nó có thể xuất hiện để làm việc. Bây giờ. Trên máy của bạn. - jalf


Các câu trả lời:


bạn cần bỏ đi độ chói:

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

cũng là câu trả lời phổ biến không hoạt động trong 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 .. điều này là không bao giờ được đề nghị ... Tôi thấy rằng g + + không cho phép điều này xảy ra .. do đó có thể là vấn đề bạn đang gặp phải.


35
2018-02-24 19:02



đã thử nhưng nó không hoạt động: \ a sẽ giữ nguyên giá trị và (* ptr) sẽ có một giá trị khác - fmsf
sử dụng g ++ trên mac btw - fmsf
int 4.1.2 nó bị chặn trong g + + nhưng không bị gcc. - sfossen
nó có thể là trình biên dịch lưu trữ giá trị của a. tạo một "const volatile a = 3;" và "ptr" a "volatile int * ptr;" - Johannes Schaub - litb
Thực tế là nó không hoạt động đáng tin cậy nên là một dấu hiệu tốt về lý do tại sao nói dối với trình biên dịch là xấu. - Ryan Graham


Chỉ cần đoán, nhưng một câu hỏi phổ biến là tại sao người ta không thể chuyển đổi int** đến một const int**, ban đầu dường như hợp lý (sau khi tất cả, bạn chỉ cần thêm một const, bình thường là ok). Lý do là nếu bạn có thể làm điều này, bạn có thể vô tình sửa đổi một const vật:

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

Đó là một kết quả rất không trực quan, nhưng cách duy nhất để đảm bảo rằng bạn không thể sửa đổi const đối tượng trong trường hợp này (lưu ý làm thế nào không có dự đoán) là để làm cho dòng 3 một lỗi.

Bạn chỉ được phép thêm const mà không có một diễn viên ở cấp độ FIRST của indirection:

int * const *ppx = &px;  // this is ok
*ppx = &x;               // but now this is an error because *ppx is 'const'

Trong C ++, không thể sửa đổi một const đối tượng mà không sử dụng một kiểu chữ nào đó. Bạn sẽ phải sử dụng dàn diễn viên kiểu C hoặc kiểu C ++ const_cast để loại bỏ const-. Bất kỳ nỗ lực nào khác để làm như vậy sẽ dẫn đến lỗi trình biên dịch ở đâu đó.


12
2018-02-24 19:19



Bây giờ, tôi làm việc qua lý luận này một lần nữa. Nó luôn làm tôi đau đầu. - Michael Burr
@Michael: phew - Tôi không đơn độc. Của tôi cũng thế! - Jonathan Leffler


Lưu ý bất kỳ nỗ lực nào để loại bỏ constness đều không được xác định theo tiêu chuẩn. Từ 7.1.5.1 của tiêu chuẩn:

Ngoại trừ bất kỳ thành viên lớp nào được khai báo   có thể thay đổi được, bất kỳ   cố gắng sửa đổi một đối tượng const   trong suốt cuộc đời của nó   kết quả trong hành vi không xác định.

Và ngay sau khi ví dụ này được sử dụng:

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

Vì vậy, trong ngắn hạn những gì bạn muốn làm là không thể sử dụng tiêu chuẩn C + +.

Hơn nữa khi trình biên dịch gặp một tuyên bố như

const int a = 3; // I promisse i won't change a

nó là miễn phí để thay thế bất kỳ sự xuất hiện của 'a' với 3 (có hiệu quả làm điều tương tự như #define a 3)


8
2018-02-24 19:17





Trở lại thời kỳ sương mù, chúng tôi lập trình viên paleo sử dụng FORTRAN. FORTRAN đã vượt qua tất cả các tham số của nó bằng cách tham chiếu và không thực hiện bất kỳ lỗi đánh máy nào. Điều này có nghĩa là khá dễ dàng để vô tình thay đổi giá trị của một hằng số chữ. Bạn có thể chuyển "3" cho SUBROUTINE, và nó sẽ quay lại thay đổi, và cứ mỗi lần từ đó mã của bạn có "3", nó sẽ thực sự hoạt động như một giá trị khác. Hãy để tôi nói cho bạn biết, đó là những lỗi khó tìm và sửa chữa.


6
2018-02-24 18:58



Điều "3" làm ngày của tôi :) - Bogdan Alexandru


Bạn đã thử cái này chưa?

ptr = const_cast<int *>(ptr_to_a);

Điều đó sẽ giúp nó biên dịch nhưng nó không thực sự do tai nạn do dàn diễn viên.


4
2018-04-19 06:43



Vâng, tôi biết nhưng tôi nghĩ rằng nó không có mặc dù - fmsf
Có vẻ như bạn sẽ nhận được câu trả lời đúng, nhưng tôi sẽ còn lâu hơn một chút trong trường hợp giải pháp không có const_cast xuất hiện. Như tôi thực sự tin rằng nó - fmsf
Điều này là không chính xác. - sfossen
trong đó không gây ra hành vi được yêu cầu. - sfossen


Trong C ++, Sử dụng 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's 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's okay. */
cout << "b = " << b << "\n"; /* prints 5 */
//int arr2[b]; /* Compilation error */

Trong C, một biến const có thể được sửa đổi thông qua con trỏ của nó; tuy nhiên nó là hành vi không xác định. Một biến const có thể không bao giờ được sử dụng như chiều dài trong một khai báo mảng.

Trong C ++, nếu một biến const được khởi tạo với một biểu thức liên tục thuần túy, thì giá trị của nó không thể được sửa đổi thông qua con trỏ của nó ngay cả sau khi cố sửa đổi, nếu không một biến const có thể được sửa đổi thông qua con trỏ của nó.

Biến const không thể tách rời thuần túy có thể được sử dụng như chiều dài trong khai báo mảng, nếu giá trị của nó lớn hơn 0.

Một biểu thức liên tục thuần túy bao gồm các toán hạng sau.

  1. Chữ số (hằng số), ví dụ: 2, 10.53

  2. Một hằng số tượng trưng được xác định bởi chỉ thị #define

  3. Một hằng số liệt kê

  4. Biến const thuần túy nghĩa là biến const được tự khởi tạo với biểu thức liên tục thuần túy.

  5. Các biến không phải biến hoặc biến biến động không được phép.


2
2018-02-24 18:58





Bạn có thể muốn sử dụng const_cast:

int *ptr = const_cast<int*>(ptr_to_a);

Tôi không chắc chắn 100% này sẽ làm việc mặc dù, tôi là một chút gỉ tại C / C ++ :-)

Một số lần đọc cho const_cast: http://msdn.microsoft.com/en-us/library/bz6at95h(VS.80).aspx


0
2018-02-24 19:10





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;

0
2018-02-24 19:24



không hoạt động, sau khi biên dịch và chạy foo vẫn là 42 - fmsf
bạn không biên dịch w / tối ưu hóa, đúng không? - dirkgently
Nó chạy tốt trên kết thúc của tôi mặc dù với VS2005: (Sẽ phải chờ đợi trước khi tôi có thể đặt bàn tay của tôi trên một gcc. - dirkgently