2017-02-19 24 views
0

Здравствуйте, я получил это предупреждение с gcc (версия 5.4.0) по программе C11 скомпилированные с помощью следующей команды:Присвоение структуры в для ошибки контура с НКУ, а не с лязгом

$ 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 '\0'. 
    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] = '\0'; 
    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

Edit: Использование memcpy вместо strncpy. Удалить const на скалярных типах.

+0

Каково определение 'str_slice'? –

+0

@AndySchweig Для ясности я переместил определение в отдельный блок кода. :) – Darnuria

+0

Еще одно вопиющее злоупотребление 'strncpy'. Вместо этого используйте 'memcpy' или' snprintf', – chqrlie

ответ

1

В структуре элемент данных len объявлен как постоянный элемент данных.

typedef struct _str_slice { 
    const char* data; 
    const uint32_t len; // end - data len of slice. 
    ^^^^^^  
} str_slice; 

Это означает, что его можно изменить, и в результате вы не можете назначить один объект структуры другому объекту структуры.

+0

Хорошо спасибо! Но если я хочу сохранить консистенцию этого поля. Как я могу сделать? Я хочу сохранить возможность передать копию этой структуры, поскольку это всего лишь один указатель и 32-битный беззнаковый int. – Darnuria

+0

@Darnuria Вы можете передать копию, потому что в этом случае создается новый временный объект. Но вы не можете назначить один объект структуры другому объекту структуры. Если вы собираетесь использовать оператор присваивания, то член данных len не будет const. –

+0

Хорошо спасибо! Я понимаю. Должен ли я сделать небольшой воспроизводимый пример и заполнить ошибку для clang? Кажется странным не получить предупреждения в clang. – Darnuria