GCC에서`문자열 상수에서 'char *'`경고로 더 이상 사용되지 않는 변환을 제거하는 방법은 무엇입니까?


409

따라서 매우 큰 코드베이스로 작업 중이며 최근에 gcc 4.3으로 업그레이드되어 이제이 경고가 트리거됩니다.

경고 : 문자열 상수에서 'char *'로의 더 이상 사용되지 않는 변환

분명히이 문제를 해결하는 올바른 방법은 다음과 같은 모든 선언을 찾는 것입니다.

char *s = "constant string";

또는 함수 호출 :

void foo(char *s);
foo("constant string");

그리고 그것들을 const char포인터로 만드십시오 . 그러나 이는 최소 564 파일을 터치하는 것을 의미합니다.이 시점에서 수행하려는 작업이 아닙니다. 지금 문제는로 실행 -werror중이므로 이러한 경고를 억제 할 방법이 필요하다는 것입니다. 어떻게해야합니까?


554 라인을 교체 할 때 sed는 좋은 친구입니다. 그래도 먼저 백업하십시오.
Matt

2
오류 메시지를 억제하는 방법과 올바른 교체 방법에 대한 토론을 살펴 보았습니다. 나는 그것에 대해 의견이 없습니다. 그러나 나는 매트가 올바른 길을 가고 있다고 생각합니다. 무엇으로 바꾸고 싶은지 정의하십시오. 올바른 정규식 만 있으면됩니다. 사본을 변경하십시오. "diff"를 사용하여 원본과 비교하십시오. sed를 사용하여 변경하는 것은 빠르고 쉽고 무료이며 diff는 빠르고 쉽고 무료입니다. 사용해보고 검토해야 할 변경 사항 수를 확인하십시오. 무엇으로 바꾸고 싶은지 게시하고 사용자가 정규식 교체를 제안하도록합니다.
Thomas Hedden

gcc 경고에 따라 문제를 해결해야하는 이유 가 전체 토론에 누락되어 있습니다. 그 이유는 David Schwartz의 답변 stackoverflow.com/questions/56522654/…에 있습니다.
andig

답변:


227

-Wno-write-stringsgcc에 전달 하면이 경고가 표시되지 않습니다.


6
pragma를 사용하여 기본 파일 단위로 비활성화 할 수 있습니까?
Priyank Bolia

18
@PriyankBolia bdonlan은 Rob Walker가 사용할 수있는 답변에 댓글을 달았습니다 #pragma GCC diagnostic ignored "-Wwrite-strings".
MasterMastic

9
API를 제어하는 ​​경우를 제외하고는 const char *를 허용하도록 서명을 변경하는 방법에 대한 아래 @John의 답변이 더 정확합니다.
jcwenger 2016 년

215
이것은 끔찍한 나쁜 관행이며, 모든 표를 얻은 것이 유감입니다. 경고는 무시되므로 무시하십시오. 경고는 "친구, 당신은 잘못 될 수있는 일을하고 있습니다, 조심하세요"라고 말하고 있습니다. "닥쳐, 내가 뭘하는지 알아요"와 같이 반응하고 싶을 때만 억제해야합니다. 유아 프로그래머에게는 해당되지 않습니다.
양자 물리학 자

9
동의합니다. 경고를 없애지 말고 John이 제공 한 솔루션을 사용하십시오. 이 답변이 너무 안타깝습니다!
Jérôme

563

문자열 리터럴을 전달하는 모든 함수 "I am a string literal"char const *대신 유형으로 사용해야합니다 char*.

무언가를 고치려면 올바르게 고치십시오.

설명:

문자열 리터럴을 사용하여 수정할 문자열을 초기화 할 수 없습니다. 문자열 리터럴은 유형이기 때문 const char*입니다. 나중에 수정할 수있는 const와 멀리 캐스팅 것은 정의되지 않은 동작 당신이 당신의 복사해야하므로, const char*문자열 char에 의해 char동적으로 할당으로 char*이를 수정하기 위해 문자열.

예:

#include <iostream>

void print(char* ch);

void print(const char* ch) {
    std::cout<<ch;
}

int main() {
    print("Hello");
    return 0;
}

25
이것이 사실이지만, char */를 올바르게 사용하지 않을 수있는 타사 API를 항상 제어 할 수는 없으므로 const char *일반적으로 캐스트합니다.
ideasman42

15
@ppumkin 불행히도, 많은 C 표준 라이브러리 문자열 함수는 char*수정되지 않는 문자열에 대해서도 인수 를 사용합니다. 매개 변수를 a로 char const*가져 와서 표준 함수에 전달하면 해당 매개 변수를 사용할 수 있습니다 char*. 라이브러리 함수가 문자열을 조작하지 않으면 const.
John

항상 가능하지 않다고해서이 경고가 일반적인 생산 코드에 나타나는 경우가 많지 않은 것은 아닙니다.
LovesTha

1
이제 솔루션과 문자열 리터럴의 기능을 완전히 이해했습니다. 그러나 다른 사람들은 그렇지 않기 때문에 설명의 필요성을 '보유'합니다
NicoBerrogorry

1
솔루션을 적용하는 방법을 이해하지 못합니다 :(
desmond13

69

비슷한 문제가 있었으므로 다음과 같이 해결했습니다.

#include <string.h>

extern void foo(char* m);

int main() {
    // warning: deprecated conversion from string constant to ‘char*’
    //foo("Hello");

    // no more warning
    char msg[] = "Hello";
    foo(msg);
}

이것이 이것을 해결하는 적절한 방법입니까? 나는 foo그것이 const char*더 나은 해결책이지만 ( foo변경되지 않기 때문에) 그것을 수용하도록 적응시킬 수 는 없다 m.


8
@elcuco, 무엇을 제안 하시겠습니까? 나는 foo를 편집 할 수 없었고 경고를 억제하지 않아도되는 해결책을 찾으려고 노력했다. 필자의 경우 후자는 운동의 문제 였지만 원래 포스터의 경우 중요해 보였습니다. 내가 알 수있는 한 내 대답은 내 조건과 OP의 조건을 동시에 해결하여 누군가에게 귀중한 답변이 될 수있는 유일한 대답입니다. 내 솔루션이 충분하지 않다고 생각되면 대안을 제공해 주시겠습니까? (이것은 foo를 편집하거나 경고를 무시하는 것을 포함하지 않습니다.)
BlackShift

우리가 foo가 제대로 코딩되었다고 가정한다면 (불행히도 'Josh Matthews'코드가 말하는 것은 아닌 것 같습니다) 이것이 최선의 해결책입니다. 함수가 실제로 문자열 'msg'를 변경 해야하는 경우 상수 문자열을 전달하면 코드가 손상되기 때문입니다. 그러나 어쨌든 오류는 이미 새 코드가 아닌 이전 코드에 있기 때문에 질문에 대답하지 않는 것 같습니다. 그래서 그는 어쨌든 이전 코드를 변경해야합니다.
João Portela

그것이 내가 취한 접근법입니다. 그리고 누군가는 경우에이 검색되는 경우 char **PyArg_ParseTupleAndKeywords내가 이런 일을 수행static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};
dashesy

@ elcuco : C ++ 정적 배열이 어떻게 작동하는지 잘 모르겠습니다. 이것은 포인터뿐만 아니라 실제로 모든 데이터를 복사합니까?
Alexander Malakhov

이 접근법은 경우에 따라 장점이있을 수 있지만, 맹목적으로 적용하는 것은 IMO가 선보다 더 해를 끼칠 가능성이 높습니다. 이것을 맹목적으로 적용하면 쉽게 매달려있는 포인터로 이어질 수 있습니다. 또한 무의미한 문자열 복사본으로 코드를 부 풀릴 것입니다.
plugwash


30

활성 코드 기반 인 경우 여전히 코드 기반을 업그레이드 할 수 있습니다. 물론 수동으로 변경을 수행하는 것은 불가능하지만이 문제는 한 번의 sed명령 으로 해결 될 수 있다고 생각합니다 . 나는 그것을 시도하지 않았으므로 소금 알갱이로 다음을 취하십시오.

find . -exec sed -E -i .backup -n \
    -e 's/char\s*\*\s*(\w+)\s*= "/char const* \1 = "/g' {} \;

이것은 모든 장소를 찾을 수는 없지만 (함수 호출을 고려하지 않아도) 문제를 완화하고 나머지 변경을 수동으로 수행 할 수있게합니다.


7
그 선언 만 경고를 해결 않으며 작동하지 어쨌든 나오지 라이닝을위한 하나를 호출 P
주앙 포르텔

25

컴파일러 스위치를 사용할 수 없습니다. 그래서 나는 이것을 돌렸다 :

char *setf = tigetstr("setf");

이에:

char *setf = tigetstr((char *)"setf");

1
+1-응용 프로그램의 lvalue를 변경할 수 없으며 rvalue 만 변경할 수 있습니다. 이것은 실제 문제를 해결하는 것으로 판명되었습니다. 다른 하나는 컴파일러의 일부 문제를 해결합니다.
elcuco

1
정말 짜증나는 건은 (CONST의 char *)로 프로토 타입을해야하는 tigetstr ()가 아닌 (문자 *)입니다
vy32

2
이 작업을 수행하면 "경고 : 'const char *'유형에서 'char *'유형으로 캐스트됩니다." 모든 경고를 없애기 위해 const_cast를 사용해야했습니다 : const_cast <char *> ( "setf")
CrouZ

2
const 캐스트 가이 페이지에서 허용되는 첫 번째 해결책이라고 생각합니다 (API 변경 제외).
rwst

25

다음은 파일에서 인라인으로 수행하는 방법이므로 Makefile을 수정할 필요가 없습니다.

// gets rid of annoying "deprecated conversion from string constant blah blah" warning
#pragma GCC diagnostic ignored "-Wwrite-strings"

그러면 나중에 ...

#pragma GCC diagnostic pop

25

바꾸다

char *str = "hello";

char *str = (char*)"hello";

또는 함수를 호출하는 경우 :

foo("hello");

이것을 다음으로 대체하십시오

foo((char*) "hello");

15

대신에:

void foo(char *s);
foo("constant string");

이것은 작동합니다 :

void foo(const char s[]);
foo("constant string");

어쨌든 일정하지 않은 문자열을 기대하는 함수에 (일정한) 문자열을 전달해서는 안되기 때문에 이것이 올바른 방법입니다!
jfla


7

Test stringconst 문자열입니다. 따라서 다음과 같이 해결할 수 있습니다.

char str[] = "Test string";

또는:

const char* str = "Test string";
printf(str);

4

왜 유형 캐스팅을 사용하지 않습니까?

(char*) "test"

2

상수 문자열에서 char 포인터로 타입 캐스팅을 수행하십시오.

char *s = (char *) "constant string";

1

C ++에서 다음을 바꾸십시오.

char *str = "hello";

와:

std::string str ("hello");

그리고 당신이 그것을 비교하고 싶다면 :

str.compare("HALLO");

1

솔루션을 적용하는 방법을 이해하지 못합니다 :( – kalmanIsAGameChanger

Arduino Sketch를 사용하면서 경고를 발생시키는 기능이있었습니다.

원래 함수 : char StrContains (char * str, char * sfind)

경고를 멈추기 위해 char * str과 char * sfind 앞에 const 를 추가했습니다 .

수정 : char StrContains (const char * str, const char * sfind).

모든 경고가 사라졌습니다.


경고에 따르면 "경고 : 문자열 상수에서 'char *'로의 더 이상 사용되지 않는 변환입니다."라는 정답입니다.
Norbert Boros

0

이 상황을보십시오 :

typedef struct tagPyTypeObject
{
    PyObject_HEAD;
    char *name;
    PrintFun print;
    AddFun add;
    HashFun hash;
} PyTypeObject;

PyTypeObject PyDict_Type=
{
    PyObject_HEAD_INIT(&PyType_Type),
    "dict",
    dict_print,
    0,
    0
};

gcc에서 이름 필드를보고 경고없이 컴파일하지만 g ++에서는 그 이유를 모르겠습니다.


gcc는 파일을 C 소스 파일로 간주하고 g ++는 -x로 대체하지 않는 한 c ++ 소스 파일로 처리합니다. 선택권. 따라서 다른 언어 인 c와 c ++는 경고 해야하는 것에 미묘한 차이가 있습니다.
zhaorufei

0

다음을 호출하여 문자열 상수에서 쓰기 가능한 문자열을 만들 수도 있습니다. strdup() .

예를 들어이 코드는 다음과 같은 경고를 생성합니다.

putenv("DEBUG=1");

그러나 다음 코드는 그렇지 않습니다 (에 전달하기 전에 힙에 문자열 사본을 만듭니다 putenv).

putenv(strdup("DEBUG=1"));

이 경우 (그리고 아마도 대부분의 경우) 경고를 끄는 것은 나쁜 생각입니다-이유가 있습니다. 다른 대안 (기본적으로 모든 문자열을 쓰기 가능하게 함)은 잠재적으로 비효율적입니다.

컴파일러가 말하는 내용을 들어보십시오!


6
또한 해당 쓰기 가능 문자열에 할당 된 메모리가 누출됩니다.
RBerteig 2016

1
그렇습니다. 그것은 의도적입니다. 위와 같이 일회성 (예 : 초기화) 코드에는 문제가 없습니다. 또는 메모리를 직접 관리하고 완료되면 해제 할 수 있습니다.
BillAtHRST

1
특정 사례는 putenv()복잡합니다. 모범 사례를 선택하는 것은 아닙니다 (적어도 적어도putenv() 답변에있는 것보다 ). 완전히 별개의 토론입니다. ( putenv()POSIX가 정의되기 전의 레거시 구현에 따라 동작에 대한 POSIX 사양에 문제가 있음에 유의하십시오 .) IIRC, 최근 (이천년) GNU C 라이브러리 릴리스에서 putenv()동작 변경 과 관련된 버그가있었습니다.
Jonathan Leffler 2016 년

0

g ++에는 -w 옵션을 사용하십시오.

예:

g ++ -w -o simple.o simple.cpp -lp 스레드

이것은 사용 중단을 피하는 것이 아니라 터미널에 경고 메시지를 표시하지 않도록합니다.

사용 중단을 방지하려면 const 키워드를 다음과 같이 사용하십시오.

const char* s="constant string";  

0

-Wno-deprecated더 이상 사용되지 않는 경고 메시지를 무시 하는 옵션을 사용하지 않는 이유는 무엇 입니까?


0

지금 문제는 내가 -Werror로 달리고 있다는 것입니다.

이것이 당신의 진짜 문제입니다. IMO. (char *)에서 (const char *)로 자동 이동하는 방법을 시도해 볼 수는 있지만 일하는 것만이 아니라 돈을 투자 할 것입니다. 최소한 일부 작업에 인간을 참여시켜야합니다. 단기적으로는 경고를 무시하고 (IMO는 그대로 두거나 수정되지 않음) -Werror 만 제거하십시오.


9
사람들이 -Werror를 사용하는 이유는 경고 수정 되도록하기 위해서입니다 . 그렇지 않으면 고정되지 않습니다.
Zan Lynx

2
사람들이 -Werror를 사용하는 이유는 장난감 프로젝트에서만 일하거나 마조히즘하기 때문입니다. 100k + LOC를 사용하는 경우 GCC 업데이트로 인해 코드를 작성하지 못하는 것은 실제 문제입니다. 디토. "-Wno-write-strings"와 같은 정크를 빌드에 추가하여 성가신 경고를 제거합니다 (이 게시물의 가장 높은 평가 의견과 같이).
James Antill


3
@ 제임스 : 흥미로운 점을 제시하지만 더 나은 방법이 있어야합니다. 경고를 즉시 수정하지 않는 것은 무의미 해 보입니다. 이전 경고를 모두 제거하지 않은 상태에서 새 코드가 새 경고를 호출 한 시점을 어떻게 알 수 있습니까? 내 경험상, 그것은 사람들이 무시해서는 안된다는 경고를 무시하게 만듭니다.
nobar

2
@James : 장난감 프로젝트는 1.5 + M LOC (다국어)입니다. nobar가 말했듯이 -Werror는 경고를 무시하지 않아야합니다. 그래야합니다. 컴파일러의 새 버전이 올라갈 때마다 모든 것을 다시 확인해야합니다. -Wno-write-strings는 파일에서 파일로 파이썬 래퍼 용 ​​Boost를 사용할 때 방금 사용됩니다. Boost를 다시 쓰지 않을 것이므로 (2017 년에는 더 이상 Boost를 사용하지 않고 C ++ 11 / 싸이 썬). 무시 된 각 경고는 이제 품질 검사를 통해 정기적으로 검토하여 코드로 방지 할 수 있는지 또는 아직 가능하지 않은지 확인해야합니다.
msn

0

도움을 주셔서 감사합니다. 여기에서 선택하면이 솔루션이 제공됩니다. 이것은 깨끗하게 컴파일됩니다. 아직 코드를 테스트하지 않았습니다. 내일 ... 아마도 ...

const char * timeServer[] = { "pool.ntp.org" }; // 0 - Worldwide 
#define WHICH_NTP            0 // Which NTP server name to use.
...
sendNTPpacket(const_cast<char*>(timeServer[WHICH_NTP])); // send an NTP packet to a server
...
void sendNTPpacket(char* address) { code }

timeServer 배열에 하나의 항목 만 있다는 것을 알고 있습니다. 그러나 더있을 수 있습니다. 나머지는 메모리를 절약하기 위해 현재 주석 처리되었습니다.


-1
PyTypeObject PyDict_Type=
{ ...

PyTypeObject PyDict_Type=
{
  PyObject_HEAD_INIT(&PyType_Type),
                     "dict",
                     dict_print,
                     0,
                     0
}; 

gcc에서 이름 필드를보고 경고없이 컴파일하지만 g ++에서는 그 이유를 모르겠습니다.

gcc (Compiling C) -Wno-write-strings가 기본적으로 활성화됩니다.

g++ (Compiling C++)-Wwrite-strings 기본적으로 활성화됩니다

이것이 다른 행동이있는 이유입니다. 우리에게 매크로를 사용 Boost_python하면 그러한 경고 가 발생합니다. 그래서 우리 -Wno-write-strings는 항상 사용하기 때문에 C ++를 컴파일 할 때 사용합니다-Werror


-1

문자열을 선언 const하면 문제가 해결됩니다.

char const*s = "constant string";
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.