Chuyển đổi không dùng C ++ từ hằng chuỗi sang 'char *'


154

Tôi có một lớp học với private char str[256];

và đối với nó, tôi có một hàm tạo rõ ràng:

explicit myClass(const char *func)
{
    strcpy(str,func);
}

Tôi gọi nó là:

myClass obj("example");

Khi tôi biên dịch này, tôi nhận được cảnh báo sau:

chuyển đổi không dùng nữa từ hằng chuỗi thành 'char *'

Tại sao chuyện này đang xảy ra?


1
Bạn nên sử dụng strncpy(str, func, 255)thay vì strcpy(str, func)cho một bản sao an toàn hơn. Và sau đó đừng quên thêm '\ 0' vào cuối chuỗi vì strncpy không thêm nó.
Patrice Bernassola

2
Vẫn an toàn hơn khi nói "strncpy (str, func, sizeof (str)); str [sizeof (str) - 1] = '\ 0';"
Warren Young

3
Tôi không nghĩ ở trên đưa ra cảnh báo mà bạn đã trích dẫn, mặc dù tôi chắc chắn mã tương tự sẽ xảy ra. Để có được câu trả lời có ý nghĩa, bạn nên đăng một ví dụ biên dịch tối thiểu để đưa ra cảnh báo.
sbi

3
@Patrice, Warren: không sử dụng strncpy, đây không phải là phiên bản an toàn hơn của strcpy. Sử dụng (hoặc thực hiện lại) strcpy_s.
Steve Jessop

Tôi đã gặp vấn đề, nó chỉ hiển thị những vấn đề này đối với bản dựng -X86 chứ không phải cho bản dựng Solaris hoặc ARM (mục tiêu) thông thường nên tôi bỏ qua điều này. Không thể tìm thấy bản sửa lỗi vì nó cũng không hiển thị cảnh báo bình thường cho mã mẫu của tôi. Cảm ơn tất cả!
mkamthan

Câu trả lời:


144

Đây là thông báo lỗi bạn thấy bất cứ khi nào bạn gặp tình huống như sau:

char* pointer_to_nonconst = "string literal";

Tại sao? Vâng, C và C ++ khác nhau về loại chuỗi ký tự. Trong C kiểu là mảng char và trong C ++, nó là mảng char không đổi . Trong mọi trường hợp, bạn không được phép thay đổi các ký tự của chuỗi ký tự, do đó, const trong C ++ không thực sự là một hạn chế mà là một điều an toàn hơn. Việc chuyển đổi từ const char*sang char*thường không thể thực hiện được nếu không có diễn viên rõ ràng vì lý do an toàn. Nhưng để tương thích ngược với C, ngôn ngữ C ++ vẫn cho phép gán một chuỗi ký tự cho mộtchar* và đưa ra cảnh báo về việc chuyển đổi này không được chấp nhận.

Vì vậy, một nơi nào đó bạn đang thiếu một hoặc nhiều consts trong chương trình của bạn cho sự chính xác. Nhưng mã bạn hiển thị cho chúng tôi không phải là vấn đề vì nó không thực hiện loại chuyển đổi không dùng nữa. Cảnh báo phải đến từ một nơi khác.


17
Thật không may khi xem xét quan điểm và bỏ phiếu cho câu hỏi này rằng OP không bao giờ cung cấp mã thực sự chứng minh vấn đề.
Shafik Yaghmour 11/03/2015

1
Bạn có thể tái tạo vấn đề với mã của OP bằng cách xóa constkhỏi hàm MyClasstạo ... sau đó bạn có thể khắc phục bằng cách thêm mặt constsau.
Theodore Murdock

145

Cảnh báo:

chuyển đổi không dùng nữa từ hằng chuỗi thành 'char *'

được đưa ra bởi vì bạn đang làm ở đâu đó (không phải trong mã bạn đã đăng) một cái gì đó như:

void foo(char* str);
foo("hello");

Vấn đề là bạn đang cố gắng chuyển đổi một chuỗi ký tự (có loại const char[]) thành char*.

Bạn có thể chuyển đổi a const char[]thành const char*vì mảng phân rã thành con trỏ, nhưng những gì bạn đang làm là tạo một hằng số biến đổi.

Chuyển đổi này có thể được cho phép để tương thích C và chỉ cung cấp cho bạn cảnh báo được đề cập.


96

Như câu trả lời không. 2 bởi fnieto - Fernando Nieto mô tả rõ ràng và chính xác rằng cảnh báo này được đưa ra bởi vì ở đâu đó trong mã của bạn bạn đang làm (không phải trong mã bạn đã đăng) giống như:

void foo(char* str);
foo("hello");

Tuy nhiên, nếu bạn muốn giữ cho mã của mình không bị cảnh báo thì chỉ cần thực hiện thay đổi tương ứng trong mã của bạn:

void foo(char* str);
foo((char *)"hello");

Đó là, chỉ đơn giản là đúc stringhằng số (char *).


17
Hoặc, thực hiện chức năng: void foo (const char * str)
Caprooja

3
@Caprooja Có khai báo param là 'con trỏ tới hằng số' cũng sẽ hoạt động trong trường hợp này. Nhưng với thay đổi này, người dùng không thể thay đổi / gán lại giá trị được lưu trữ tại địa chỉ bằng cách sử dụng con trỏ 'str' mà người dùng có thể thực hiện trong phần triển khai. Vì vậy, đó là một cái gì đó bạn có thể muốn tìm ra.
sactiw

1
@sactiw Có lý do nào để giữ nguyên trạng void foo(char* str)không? Tôi nghĩ chúng ta không thể modity strtrong foodù sao, ngay cả những tham số được viết dưới dạng không const.
kgf3JfUtW

37

Có 3 giải pháp:

Giải pháp 1:

const char *x = "foo bar";

Giải pháp 2:

char *x = (char *)"foo bar";

Giải pháp 3:

char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");

Mảng cũng có thể được sử dụng thay cho con trỏ vì một mảng đã là một con trỏ không đổi.


7
Đối với giải pháp 3, có strdup. Không giống như mã của bạn, nó sẽ phân bổ không gian cho ký tự NUL kết thúc và không vượt quá phân bổ.
Ben Voigt


Trên thực tế, giải pháp 2 có thể là: char * x = static_cast <char *> ("foo bar") trong C ++.
Kehe CAI

3
Anil bạn sẽ bao giờ tích hợp các ý kiến ​​vào câu trả lời của bạn? Giải pháp 3 vẫn sai một cách nguy hiểm.
Các cuộc đua nhẹ nhàng trong quỹ đạo

@LightnessRacesinOrbit Bạn có thể vui lòng cung cấp câu trả lời không? Tôi không hiểu tại sao bạn nói Giải pháp 2 và 3 phải tránh và sai lầm nguy hiểm.
Gladclef

4

Trong thực tế, một chuỗi hằng số theo nghĩa đen không phải là const char * hay char * mà là char []. Nó khá lạ nhưng được ghi lại trong thông số kỹ thuật của c ++; Nếu bạn sửa đổi nó, hành vi không được xác định bởi vì trình biên dịch có thể lưu trữ nó trong đoạn mã.


5
Tôi sẽ nói đó là const char [] vì như một giá trị bạn không thể sửa đổi nó.
fnieto - Fernando Nieto

3

Có lẽ bạn có thể thử điều này:

void foo(const char* str) 
{
    // Do something
}

foo("Hello")

Nó làm việc cho tôi


2

Tôi giải quyết vấn đề này bằng cách thêm macro này vào đầu mã, ở đâu đó. Hoặc thêm nó vào <iostream>, hehe.

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())

8
"Hoặc thêm nó vào <iostream>" Cái gì?!
Các cuộc đua nhẹ nhàng trong quỹ đạo

Có ", hehe" đó là vì bất kỳ lý do gì đã được chỉnh sửa (ngụ ý rằng đó là một trò đùa)
chơi

C_TEXTsẽ tốt cho một lệnh gọi hàm ( foo(C_TEXT("foo"));), nhưng sẽ khóc vì hành vi không xác định nếu giá trị được lưu trữ trong một biến như char *x = C_TEXT("foo");- bất kỳ việc sử dụng nào x(ngoài việc gán) là hành vi không xác định vì bộ nhớ mà nó trỏ đến đã được giải phóng.
Martin Bonner hỗ trợ Monica

1

Một lý do cho vấn đề này (thậm chí còn khó phát hiện hơn vấn đề với char* str = "some string"- mà những người khác đã giải thích) là khi bạn đang sử dụng constexpr.

constexpr char* str = "some string";

Có vẻ như nó sẽ hành xử tương tự const char* str, và do đó sẽ không gây ra cảnh báo, như nó xảy ra trước đây char*, nhưng nó thay vào đó hành xử như char* const str.

Chi tiết

Con trỏ không đổi, và con trỏ đến một hằng. Sự khác biệt giữa const char* str, và char* const strcó thể được giải thích như sau.

  1. const char* str: Khai báo str là con trỏ tới const char. Điều này có nghĩa là dữ liệu mà con trỏ này trỏ đến nó không đổi. Con trỏ có thể được sửa đổi, nhưng mọi nỗ lực sửa đổi dữ liệu sẽ gây ra lỗi biên dịch.
    1. str++ ;: GIÁ TRỊ . Chúng tôi đang sửa đổi con trỏ, và không phải dữ liệu được trỏ đến.
    2. *str = 'a';: THAM GIA . Chúng tôi đang cố gắng sửa đổi dữ liệu được trỏ đến.
  2. char* const str: Khai báo str là con trỏ const tới char. Điều này có nghĩa là điểm đó không đổi, nhưng dữ liệu được trỏ quá thì không. Con trỏ không thể được sửa đổi nhưng chúng ta có thể sửa đổi dữ liệu bằng cách sử dụng con trỏ.
    1. str++ ;: THAM GIA . Chúng tôi đang cố gắng sửa đổi biến con trỏ, đó là một hằng số.
    2. *str = 'a';: GIÁ TRỊ . Chúng tôi đang cố gắng sửa đổi dữ liệu được trỏ đến. Trong trường hợp của chúng tôi, điều này sẽ không gây ra lỗi biên dịch, nhưng sẽ gây ra lỗi thời gian chạy , vì chuỗi có thể sẽ đi vào phần chỉ đọc của tệp nhị phân được biên dịch. Tuyên bố này sẽ có ý nghĩa nếu chúng ta có bộ nhớ được phân bổ động, ví dụ. char* const str = new char[5];.
  3. const char* const str: Khai báo str là con trỏ const cho const char. Trong trường hợp này, chúng tôi không thể sửa đổi con trỏ, cũng như dữ liệu được trỏ đến.
    1. str++ ;: THAM GIA . Chúng tôi đang cố gắng sửa đổi biến con trỏ, đó là một hằng số.
    2. *str = 'a';: THAM GIA . Chúng tôi đang cố gắng sửa đổi dữ liệu được trỏ bởi con trỏ này, đây cũng là hằng số.

Trong trường hợp của tôi, vấn đề là tôi đã mong đợi constexpr char* strcư xử như const char* str, và khôngchar* const str , vì về mặt trực quan, nó có vẻ gần với cái trước hơn.

Ngoài ra, cảnh báo được tạo ra constexpr char* str = "some string"là hơi khác với char* str = "some string".

  1. Trình biên dịch cảnh báo cho constexpr char* str = "some string":ISO C++11 does not allow conversion from string literal to 'char *const'
  2. Trình biên dịch cảnh báo cho char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.

tiền boa

Bạn có thể sử dụng C gibberish converter Trình chuyển đổi tiếng Anh để chuyển đổi các Ckhai báo thành các câu tiếng Anh dễ hiểu và ngược lại. Đây là một Ccông cụ duy nhất và do đó sẽ không hỗ trợ những thứ (như constexpr) dành riêng cho C++.


0

Tôi cũng gặp vấn đề tương tự. Và những gì tôi đơn giản đã làm chỉ là thêm const char * thay vì char *. Và vấn đề đã được giải quyết. Như những người khác đã đề cập ở trên, đó là một lỗi tương thích. C coi các chuỗi là mảng char trong khi C ++ coi chúng là mảng const char.


0

Để biết giá trị của nó, tôi thấy lớp trình bao bọc đơn giản này hữu ích cho việc chuyển đổi chuỗi C ++ thành char *:

class StringWrapper {
    std::vector<char> vec;
public:
    StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
    }

    char *getChars() {
        return &vec[0];
    }
};

-1

Sau đây minh họa giải pháp, gán chuỗi của bạn cho một con trỏ biến thành một mảng char không đổi (một chuỗi là một con trỏ không đổi cho một mảng không đổi của thông tin char - plus length):

#include <iostream>

void Swap(const char * & left, const char * & right) {
    const char *const temp = left;
    left = right;
    right = temp;
}

int main() {
    const char * x = "Hello"; // These works because you are making a variable
    const char * y = "World"; // pointer to a constant string
    std::cout << "x = " << x << ", y = " << y << '\n';
    Swap(x, y);
    std::cout << "x = " << x << ", y = " << y << '\n';
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.