@Isalamon По сути, все, что хранится в сыром виде в хранилище (первичном или вторичном) компьютера, называется «данными». Адрес других данных также является данными, поэтому указатель хранит данные.

аписании проекта я столкнулся со странной проблемой.

Это минимальный код, который мне удалось написать, чтобы воссоздать проблему. Я намеренно храню фактическую строку вместо чего-то другого, с достаточным количеством выделенного пространства.

// #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stddef.h> // For offsetof()

typedef struct _pack{
    // The type of `c` doesn't matter as long as it's inside of a struct.
    int64_t c;
} pack;

int main(){
    pack *p;
    char str[9] = "aaaaaaaa"; // Input
    size_t len = offsetof(pack, c) + (strlen(str) + 1);
    p = malloc(len);
    // Version 1: crash
        strcpy((char*)&(p->c), str);
    // Version 2: crash
        strncpy((char*)&(p->c), str, strlen(str)+1);
    // Version 3: works!
        memcpy((char*)&(p->c), str, strlen(str)+1);
    // puts((char*)&(p->c));
    free(p);
  return 0;
}

Приведенный выше код сбивает меня с толку:

С участиемgcc/clang -O0, обеstrcpy() а такжеmemcpy() работает на Linux / WSL, аputs() ниже дает все, что я вошел.С участиемclang -O0 на OSXкод вылетает сstrcpy().С участиемgcc/clang -O2 или же-O3 на Ubuntu / Fedora / WSL, кодсбой (!!) вstrcpy(), покаmemcpy() работает хорошо.С участиемgcc.exe в Windows код работает хорошо независимо от уровня оптимизации.

Также я нашел некоторые другие черты кода:

(Это выглядит как)минимальный вход для воспроизведения аварии составляет 9 байтов (включая нулевой терминатор), или1+sizeof(p->c), При такой длине (или дольше) сбой гарантирован (Дорогой я ...).Даже если я выделю дополнительное пространство (до 1 МБ) вmalloc()это не помогает Вышеуказанное поведение не меняется вообще.strncpy() ведет себя точно так же, даже с правильной длиной, указанной в третьем аргументе.Указатель, похоже, не имеет значения. Если член структурыchar *c изменяется вlong long c (или жеint64_t), поведение остается прежним. (Обновление: уже изменилось).

Сообщение о сбое не выглядит обычным. Много дополнительной информации дается вместе.

Я перепробовал все эти компиляторы, и они не имели никакого значения:

GCC 5.4.0 (Ubuntu / Fedora / OS X / WSL, все 64-битные)GCC 6.3.0 (только Ubuntu)GCC 7.2.0 (Android, norepro ???) (это GCC изC4droid)Clang 5.0.0 (Ubuntu / OS X)MinGW GCC 6.3.0 (Windows 7/10, оба x64)

Кроме того, эта пользовательская функция копирования строк, которая выглядит в точности как стандартная, хорошо работает с любой конфигурацией компилятора, упомянутой выше:

char* my_strcpy(char *d, const char* s){
    char *r = d;
    while (*s){
        *(d++) = *(s++);
    }
    *d = '\0';
    return r;
}
Вопросов:Почемуstrcpy() провал? Как это может?Почему происходит сбой только при включенной оптимизации?Почему неmemcpy() потерпеть неудачу независимо от-O Уровень ??

* Если вы хотите обсудить нарушение доступа к элементам структуры, пожалуйста, не стесняйтесьВот.

Частьobjdump -dВывод аварийного исполняемого файла (на WSL):

Постскриптум Сначала я хочу написать структуру, последний элемент которой является указателем на динамически выделенное пространство (для строки). Когда я пишу структуру в файл, я не могу написать указатель. Я должен написать фактическую строку. Поэтому я пришел к такому решению: принудительно хранить строку вместо указателя.

Также, пожалуйста, не жалуйтесь наgets(), Я не использую его в своем проекте, но приведенный выше пример кода.

Ответы на вопрос(6)

Ваш ответ на вопрос