경고: 문자열 리터럴과 비교하면 지정되지 않은 동작이 발생합니다.
C에 Linux용 간이 셸을 작성하는 프로젝트를 시작하고 있습니다.저는 C도 Linux도 전혀 능숙하지 않기 때문에 좋은 아이디어라고 판단했습니다.
파서부터 이미 몇 가지 문제가 발생했습니다.
코드는 간단해야 하기 때문에 코멘트를 넣지 않았습니다.
"WARNING HERE"로 코멘트된 행에 "문자열 리터럴과 비교하면 지정되지 않은 동작이 발생한다"라는 경고가 gcc와 함께 표시됩니다(아래 코드 참조).
이것이 왜 경고를 발생시키는지 알 수 없지만, 진짜 문제는 "<"를 "<"와 비교해도 만약의 경우 안에 들어가지 않는다는 것입니다.
설명한 문제에 대한 답을 찾고 있습니다만, 코드에 개선해야 할 점이 있으면 그렇게 말씀해 주십시오.저는 그다지 능숙하지 않으며, 이것은 아직 진행 중인 작업(또는 시작 단계에서의 작업)이라는 점을 유념하십시오.
잘 부탁드립니다.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
typedef enum {false, true} bool;
typedef struct {
char **arg;
char *infile;
char *outfile;
int background;
} Command_Info;
int parse_cmd(char *cmd_line, Command_Info *cmd_info)
{
char *arg;
char *args[100];
int i = 0;
arg = strtok(cmd_line, " \n");
while (arg != NULL) {
args[i] = arg;
arg = strtok(NULL, " \n");
i++;
}
int num_elems = i;
cmd_info->infile = NULL;
cmd_info->outfile = NULL;
cmd_info->background = 0;
int iarg = 0;
for (i = 0; i < num_elems; i++)
{
if (args[i] == "&") //WARNING HERE
return -1;
else if (args[i] == "<") //WARNING HERE
if (args[i+1] != NULL)
cmd_info->infile = args[i+1];
else
return -1;
else if (args[i] == ">") //WARNING HERE
if (args[i+1] != NULL)
cmd_info->outfile = args[i+1];
else
return -1;
else
cmd_info->arg[iarg++] = args[i];
}
cmd_info->arg[iarg] = NULL;
return 0;
}
void print_cmd(Command_Info *cmd_info)
{
int i;
for (i = 0; cmd_info->arg[i] != NULL; i++)
printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);
printf("arg[%d]=\"%s\"\n", i, cmd_info->arg[i]);
printf("infile=\"%s\"\n", cmd_info->infile);
printf("outfile=\"%s\"\n", cmd_info->outfile);
printf("background=\"%d\"\n", cmd_info->background);
}
int main(int argc, char* argv[])
{
char cmd_line[100];
Command_Info cmd_info;
printf(">>> ");
fgets(cmd_line, 100, stdin);
parse_cmd(cmd_line, &cmd_info);
print_cmd(&cmd_info);
return 0;
}
하려고 합니다.strcmp() == 0
한 비교가 비교하다==
포인터가 같은 경우(이 경우에는 해당되지 않음)를 비교합니다.
args[i]
terminated 에 대한 입니다. 「」라고 하는 의미입니다."&"
★★★★★★★★★★★★★★★★★」"<"
.
.argc[i] == "&"
는, 2개의 포인터가 같은지를 확인합니다(같은 메모리 위치를 가리키고 있습니다).
.strcmp( argc[i], "&") == 0
두 문자열의 내용이 동일한지 확인합니다.
이 있다'a'
★★★★★★★★★★★★★★★★★」"a"
:
'a'
입니다.a
."a"
는, 메모리 위치의 주소는 다음과 같습니다."a"
저장된다(일반적으로 프로그램 메모리 공간의 데이터 섹션에 있음).위치에는 2바이트입니다.★★★★'a'
및 문자열의 늘 터미네이터를 지정합니다.
if (args[i] == "&")
좋아, 이걸로 뭘 할 수 있는지 알아보자.
포인터의 입니다. 이번에는.args[i]
~ 에 (지 ( 포인터)"&"
(일부러) 이 일 수 있는 은 당신이 에 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아.args[i]="&"
★★★★★★★★★★★★★."&"
모든 곳에서 같은 장소를 가리킬 수 있는 것은 아닙니다.
이 있는 은 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.strcmp
전체 문자열을 비교하거나 하고 싶은 것을 비교하다if (*args[i] == '&')
의 첫 글자를 비교하다args[i]
에 줄을 매다&
성격
이것은 오래된 질문이지만, 최근 누군가에게 설명해야 했기 때문에, 여기에 답을 기록하는 것이 적어도 C의 구조를 이해하는 데 도움이 될 것이라고 생각했습니다.
스트링 리터럴은 다음과 같습니다.
"a"
또는
"This is a string"
프로그램의 텍스트 또는 데이터 세그먼트에 저장됩니다.
C의 문자열은 실제로는 차자에 대한 포인터이며 NUL 문자가 발생할 때까지 메모리 내의 후속 문자로 인식됩니다.즉, C는 현에 대해 잘 모릅니다.
그래서 만약에 내가
char *s1 = "This is a string";
다음으로 s1은 문자열의 첫 번째 바이트에 대한 포인터입니다.
이제, 만약 내가
char *s2 = "This is a string";
또한 프로그램의 텍스트 또는 데이터 세그먼트에서 해당 문자열의 첫 번째 바이트에 대한 포인터이기도 합니다.
하지만 만약 내가
char *s3 = malloc( 17 );
strcpy(s3, "This is a string");
그러면 s3는 다른 문자열의 모든 바이트를 복사하는 메모리 내의 다른 위치에 대한 포인터입니다.
예시:
컴파일러가 올바르게 지적하고 있듯이, 이것을 실행해서는 안 됩니다.다만, 다음과 같이 평가됩니다.
s1 == s2 // True: we are comparing two pointers that contain the same address
하지만 다음은 거짓으로 평가될 것입니다.
s1 == s3 // False: Comparing two pointers that don't hold the same address.
그리고 다음과 같은 것이 매력적일 수 있습니다.
struct Vehicle{
char *type;
// other stuff
}
if( type == "Car" )
//blah1
else if( type == "Motorcycle )
//blah2
그것은 효과가 보장되는 것이 아니기 때문에 해서는 안 된다.이 유형은 항상 문자열 리터럴을 사용하여 설정됩니다.
시험해 봤는데 효과가 있어요.내가 하면
A.type = "Car";
그리고 blah1이 실행되고 'Motorcycle'도 마찬가지입니다.그리고 당신은 이런 것들을 할 수 있을 것이다.
if( A.type == B.type )
하지만 이건 정말 끔찍해요왜 효과가 있는지 아는 것이 흥미롭고, 왜 하면 안 되는지 이해하는 데 도움이 되기 때문에 이 글을 씁니다.
솔루션:
당신의 경우, 당신이 하고 싶은 것은,strcmp(a,b) == 0
교체하다a == b
이 예에서는 열거형을 사용해야 합니다.
enum type {CAR = 0, MOTORCYCLE = 1}
앞의 문자열은 활자를 인쇄할 수 있기 때문에 도움이 됩니다.그러면 이런 배열이 있을 수 있습니다.
char *types[] = {"Car", "Motorcycle"};
그러고 보니 유형 배열에서 동일한 순서를 유지하도록 주의해야 하기 때문에 오류가 발생하기 쉽습니다.
따라서 하는 것이 더 나을 수 있습니다.
char *getTypeString(int type)
{
switch(type)
case CAR: return "Car";
case MOTORCYCLE: return "Motorcycle"
default: return NULL;
}
스트링을 비교할 수 없습니다.==
C의 경우 문자열은 단지 (제로 종단된) 배열이므로 문자열 함수를 사용하여 비교해야 합니다.strcmp() 및 strncmp()의 man 페이지를 참조해 주세요.
문자를 비교하려면 문자열이 아닌 문자와 비교해야 합니다. "a"
입니다.a
(2바이트)를 차지합니다a
및 를 지정합니다.단, 「」는 「」를 참조해 주세요.a
라고 표현합니다.'a'
로 있습니다.
나는 오늘 클라이언트 프로그램과 함께 일하면서 이 문제를 우연히 발견했다.이 프로그램은 VS6.0에서 다음을 사용하여 정상적으로 동작합니다(약간 변경했습니다).
//
// This is the one include file that every user-written Nextest programs needs.
// Patcom-generated files will also look for this file.
//
#include "stdio.h"
#define IS_NONE( a_key ) ( ( a_key == "none" || a_key == "N/A" ) ? TRUE : FALSE )
//
// Note in my environment we have output() which is printf which adds /n at the end
//
main {
char *psNameNone = "none";
char *psNameNA = "N/A";
char *psNameCAT = "CAT";
if (IS_NONE(psNameNone) ) {
output("psNameNone Matches NONE");
output("%s psNameNoneAddr 0x%x \"none\" addr 0x%X",
psNameNone,psNameNone,
"none");
} else {
output("psNameNone Does Not Match None");
output("%s psNameNoneAddr 0x%x \"none\" addr 0x%X",
psNameNone,psNameNone,
"none");
}
if (IS_NONE(psNameNA) ) {
output("psNameNA Matches N/A");
output("%s psNameNA 0x%x \"N/A\" addr 0x%X",
psNameNA,psNameNA,
"N/A");
} else {
output("psNameNone Does Not Match N/A");
output("%s psNameNA 0x%x \"N/A\" addr 0x%X",
psNameNA,psNameNA,
"N/A");
}
if (IS_NONE(psNameCAT)) {
output("psNameNA Matches CAT");
output("%s psNameNA 0x%x \"CAT\" addr 0x%X",
psNameNone,psNameNone,
"CAT");
} else {
output("psNameNA does not match CAT");
output("%s psNameNA 0x%x \"CAT\" addr 0x%X",
psNameNone,psNameNone,
"CAT");
}
}
VS6.0에 내장된 경우 편집 후 계속하기 프로그램 데이터베이스를 사용합니다.는 동작하고 있는 것처럼 보입니다.이 설정을 사용하면 STRING 풀링이 활성화되고 컴파일러는 모든 STRING 포인터를 POINT TO THE SAME ADDRESS로 최적화하여 동작합니다.컴파일 시간 후 즉시 작성된 문자열은 주소가 다르므로 비교에 실패합니다. 설정을 Program Database only(프로그램 데이터베이스만)로 변경하면 프로그램이 구축되어 오류가 발생합니다.
clang은 오류 보고 및 복구에 이점이 있습니다.
$ clang errors.c errors.c:36:21: warning: result of comparison against a string literal is unspecified (use strcmp instead) if (args[i] == "&") //WARNING HERE ^~ ~~~ strcmp( , ) == 0 errors.c:38:26: warning: result of comparison against a string literal is unspecified (use strcmp instead) else if (args[i] == "<") //WARNING HERE ^~ ~~~ strcmp( , ) == 0 errors.c:44:26: warning: result of comparison against a string literal is unspecified (use strcmp instead) else if (args[i] == ">") //WARNING HERE ^~ ~~~ strcmp( , ) == 0
합니다.
x == y
타타에strcmp(x,y) == 0
.gengetopt는 명령줄 옵션 파서를 대신 작성합니다.
언급URL : https://stackoverflow.com/questions/2603039/warning-comparison-with-string-literals-results-in-unspecified-behaviour
'source' 카테고리의 다른 글
공유 호스팅에 larabel + vuej 도입 (0) | 2022.08.18 |
---|---|
부호 있는 문자와 부호 없는 문자의 차이 (0) | 2022.08.18 |
Java에서의 Runnable 인터페이스와 Callable 인터페이스의 차이점 (0) | 2022.08.18 |
Swift 프로토콜과 Java 인터페이스 비교 (0) | 2022.08.18 |
Java의 Object 클래스에서 인터페이스를 상속합니까? (0) | 2022.08.18 |