使用 gcc 而不是使用 clang 在 for 循环错误中分配结构
Assignment of a struct in a for loop error with gcc and not with clang
你好,我在使用以下命令编译的 C11 程序上收到 gcc
(版本 5.4.0)的警告:
$ gcc -g -Wall -std=c11 main.c -o minishell
main.c: In function ‘process_new’:
main.c:184:10: error: assignment of read-only variable ‘s’
s = slice_next(s, ':')) {
但 clang
(版本 3.8.0)没有任何内容:
$ clang -g -Wall -std=c11 main.c -o minishell # Compile without warning.
我在 Ubuntu 16.04.
这是代码
// The loop that generate the warning with gcc.
for (str_slice s = slice_at(paths, ':');
!slice_empty(s);
s = slice_next(s, ':')) {
// ^ Gcc complains here.
const char *full_path = build_full_path(progname, s);
/* I use with full_path but nothing with s after this point. */
// There is no aliasing on full_path at this point.
free((void *)full_path); .
}
这里是str_slice
的定义:
typedef struct _str_slice {
const char* data;
const uint32_t len; // end - data len of slice.
//^^^^^ Source of gcc warning.
} str_slice;
以及使用它的函数:
inline
uint32_t slice_len(const str_slice slice) {
return slice.len;
}
inline
const char* slice_data(const str_slice s) {
return s.data;
}
inline
str_slice slice_new(const char* data, uint32_t len) {
return (str_slice) { data, len };
}
inline
str_slice slice_at(const char* data, const char c) {
const char* end = strchr(data, c);
return slice_new(data, end - data);
}
inline
str_slice slice_next(const str_slice s, const char c) {
const char* data = slice_data(s) + slice_len(s) + 1; // skip c
const char* end = strchr(data, c);
if (end != NULL) {
return slice_new(data, end - data);
} else {
return slice_new(NULL, 0);
}
}
inline
bool slice_empty(const str_slice s) {
return s.len == 0;
}
如有必要,有关 build_full_path
的代码
const char* build_full_path(const char* progname, const str_slice slice) {
size_t len_progname = strlen(progname);
// Save additional 2 bytes for adding '/' and '[=15=]'.
size_t full_path_size = len_progname + slice.len + 2;
size_t malloc_size = sizeof(char) * full_path_size;
char *full_path = malloc(malloc_size);
full_path[full_path_size - 1] = '[=15=]';
memcpy(full_path, slice.data, slice.len);
full_path[slice.len] = '/';
memcpy(full_path + slice.len + 1, progname, len_progname);
return (const char *) full_path;
}
当用 clang 编译时,我得到了一个具有良好行为的可执行文件。
所以我做错了什么?或者我发现了一个错误?
这里是我程序的完整代码(已过时):https://gist.github.com/darnuria/12af88c509310c2b40e0031522882720
编辑:使用 memcpy
而不是 strncpy
。删除标量类型的 const。
在结构中,数据成员 len
被声明为常量数据成员。
typedef struct _str_slice {
const char* data;
const uint32_t len; // end - data len of slice.
^^^^^^
} str_slice;
这意味着它可以更改,因此您不能将结构的一个对象分配给结构的另一个对象。
你好,我在使用以下命令编译的 C11 程序上收到 gcc
(版本 5.4.0)的警告:
$ gcc -g -Wall -std=c11 main.c -o minishell
main.c: In function ‘process_new’:
main.c:184:10: error: assignment of read-only variable ‘s’
s = slice_next(s, ':')) {
但 clang
(版本 3.8.0)没有任何内容:
$ clang -g -Wall -std=c11 main.c -o minishell # Compile without warning.
我在 Ubuntu 16.04.
这是代码
// The loop that generate the warning with gcc.
for (str_slice s = slice_at(paths, ':');
!slice_empty(s);
s = slice_next(s, ':')) {
// ^ Gcc complains here.
const char *full_path = build_full_path(progname, s);
/* I use with full_path but nothing with s after this point. */
// There is no aliasing on full_path at this point.
free((void *)full_path); .
}
这里是str_slice
的定义:
typedef struct _str_slice {
const char* data;
const uint32_t len; // end - data len of slice.
//^^^^^ Source of gcc warning.
} str_slice;
以及使用它的函数:
inline
uint32_t slice_len(const str_slice slice) {
return slice.len;
}
inline
const char* slice_data(const str_slice s) {
return s.data;
}
inline
str_slice slice_new(const char* data, uint32_t len) {
return (str_slice) { data, len };
}
inline
str_slice slice_at(const char* data, const char c) {
const char* end = strchr(data, c);
return slice_new(data, end - data);
}
inline
str_slice slice_next(const str_slice s, const char c) {
const char* data = slice_data(s) + slice_len(s) + 1; // skip c
const char* end = strchr(data, c);
if (end != NULL) {
return slice_new(data, end - data);
} else {
return slice_new(NULL, 0);
}
}
inline
bool slice_empty(const str_slice s) {
return s.len == 0;
}
如有必要,有关 build_full_path
const char* build_full_path(const char* progname, const str_slice slice) {
size_t len_progname = strlen(progname);
// Save additional 2 bytes for adding '/' and '[=15=]'.
size_t full_path_size = len_progname + slice.len + 2;
size_t malloc_size = sizeof(char) * full_path_size;
char *full_path = malloc(malloc_size);
full_path[full_path_size - 1] = '[=15=]';
memcpy(full_path, slice.data, slice.len);
full_path[slice.len] = '/';
memcpy(full_path + slice.len + 1, progname, len_progname);
return (const char *) full_path;
}
当用 clang 编译时,我得到了一个具有良好行为的可执行文件。 所以我做错了什么?或者我发现了一个错误?
这里是我程序的完整代码(已过时):https://gist.github.com/darnuria/12af88c509310c2b40e0031522882720
编辑:使用 memcpy
而不是 strncpy
。删除标量类型的 const。
在结构中,数据成员 len
被声明为常量数据成员。
typedef struct _str_slice {
const char* data;
const uint32_t len; // end - data len of slice.
^^^^^^
} str_slice;
这意味着它可以更改,因此您不能将结构的一个对象分配给结构的另一个对象。