приведение содержимого массива в арифметический тип в C - PullRequest
0 голосов
/ 19 января 2012

Я сталкиваюсь со странным поведением при приведении (или даже более разыменовании) отдельных элементов из массива в один арифметический тип.

Вот сокращенный контрольный пример:

void test1()
{
    unsigned char test[10] = {0};
    unsigned long i=0xffffffff;

    *((unsigned long *)(&test[3])) = i;


    int it;

    for ( it = 0 ; it < 10 ; it++ )

    {
        printf("%02x ", test[it]);

    }
}
void test2()
{
    unsigned char test[10] = {0};
    unsigned char test2[10] = {0};
    test[2]=0xFF;
    test[3]=0xFF;

    *((unsigned short *)(&test2[1])) = *((unsigned short *)(&test[2]));


    int it;

    for ( it = 0 ; it < 10 ; it++ )

    {
        printf("%02x ", test2[it]);

    }
}

Подробно это в основном это выражение:

    *((unsigned short *)(&test2[1]))

Я получаю нарушения прав доступа на некоторых других платформах (в основном, на встраиваемых платформах, таких как PIC24).

Итак, мой вопрос: соответствует ли это C? Я не могу найти ничего в C-стандарте, но, возможно, я только слепой.

Знаете ли вы какие-либо альтернативы, выполняющие эту операцию без такого приведения (циклическое копирование / разворачивание байт в байт и т. Д. Не предусмотрено!) И где мне не нужно знать текущий порядок байтов платформы?

Спасибо!

Ответы [ 3 ]

5 голосов
/ 19 января 2012
 *((unsigned short *)(&test2[1]))

Это неопределенное поведение, вы нарушаете правила выравнивания и псевдонимов.Не делайте этого.

Ваш test2 объект является массивом unsigned char, и через приведение вы получаете доступ к его элементам как unsigned short объектам.Нет гарантии, что unsigned char требование выравнивания такое же, как unsigned short требование выравнивания.

В стандарте C вы можете найти информацию о выравнивании в 6.3.2.3p7 (C99) и о правилах алиасинга в 6.5p7.

Хорошее эмпирическое правило всегда должно быть очень осторожным вналичие приведений в левой части оператора =.

3 голосов
/ 19 января 2012

Строка *((unsigned long *)(&test[3])) = i; имеет неопределенное поведение.это зависит от sizeof (long) и порядкового номера вашей машины.Как правило, вы не должны приводить между различными типами указателей (кроме void*).

1 голос
/ 19 января 2012

Проблема здесь почти наверняка в том, что вы делаете нелицензированный доступ.Если символы - 1 байт, а шорты - 2 (что вполне вероятно), то вы выполняете операцию короткой записи нечетного числа.Это не всегда поддерживается и именно поэтому вы, скорее всего, получаете нарушение прав доступа.Если вы действительно хотите это сделать (чего, вероятно, нет), вы можете дополнить массив char, сделав его на один символ длиннее спереди, а затем просто не использовать этот первый символ (трактуйте массив как 1-индексированный, а не 0-indexed) и это, вероятно, будет работать на платформах, где это не так, но даже это не гарантировано.

...