2013-07-03 2 views
0
#include "stdio.h" 

typedef struct CustomStruct 
{ 
    short Element1[10]; 
}CustomStruct; 

void F2(char* Y) 
{ 
    *Y=0x00; 
    Y++; 
    *Y=0x1F;  
} 

void F1(CustomStruct* X) 
{ 
    F2((char *)X); 
    printf("s = %x\n", (*X).Element1[0]); 
} 

int main(void) 
{ 
    CustomStruct s; 
    F1(&s); 

    return 0; 
} 

Приведенный выше код C печатает 0x1f00 при компиляции и запуске на моем ПК.Указатели Кастинг Endianness

Но когда я прокручиваю его во встроенную цель (uController) и отлаживаю, я нахожу это (*X).Element1[0] = 0x001f.

1- Почему результаты различны на ПК и встроенной цели?

2- Что я могу изменить в этом коде, чтобы он печатал 0x001f в корпусе ПК, без изменения ядра кода (путем добавления опции компилятора или чего-то еще).

ответ

2

Портативный способ изменить определение F2:

void F2(short * p) 
{ 
    *p = 0x1F; 
} 

void F1(CustomStruct* X) 
{ 
    F2(&X.Element1[0]); 
    printf("s = %x\n", (*X).Element1[0]); 
} 

Когда вы переосмысливать объект как массив символов, вы подвергаете детали реализации о представлении, которое по сути является непереносимым и ... зависит от реализации.

Если вам необходимо выполнить ввод/вывод, то есть интерфейс с фиксированным, указанным внешним форматом провода, используйте функции, такие как htons and ntohs, чтобы преобразовать и оставить спецификацию платформы в вашей библиотеке.

+0

Большое спасибо. Проблема в том, что по многим причинам я могу только изменить тело функции F2. Я не могу изменить его прототип. Есть ли способ найти размер Y перед тем, как он был заперт или что-то еще? –

+0

Если вы знаете, что вы всегда будете передавать адрес короткого замыкания на F2, вы можете указать его параметр на короткий внутри тела функции и присвоить ему значение. Это сделает его совместимым с другими видами использования этой памяти в вашей программе как краткое, но потенциально несовместимым с обменом побочных сырых данных с другой системой, которая может иметь различную направленность. –

1

Похоже, что компьютер немного ориентирован, а цель - либо большой, либо имеет 16-битный символ.

Невозможно изменить код C на ПК, если вы не замените ссылки char * ссылками short * и, возможно, используете макросы, чтобы абстрагировать различия между вашим микроконтроллером и ПК.

Например, вы можете сделать макрос PACK_BYTES(hi, lo), который упаковывает два байта в короткий то же самое, независимо от машинного конца. Ваш пример будет следующим:

#include "stdio.h" 

#define PACK_BYTES(hi,lo) (((short)((hi) & 0xFF)) << 8 | (0xFF & (lo))) 

typedef struct CustomStruct 
{ 
    short Element1[10]; 
}CustomStruct; 

void F2(short* Y) 
{ 
    *Y = PACK_BYTES(0x00, 0x1F); 
} 

void F1(CustomStruct* X) 
{ 
    F2(&(X->Element1[0])); 
    printf("s = %x\n", (*X).Element1[0]); 
} 

int main(void) 
{ 
    CustomStruct s; 
    F1(&s); 

    return 0; 
} 
+0

Большое вам спасибо. Проблема в том, что по многим причинам я могу только изменить тело функции F2. Я не могу изменить его прототип. Есть ли способ найти размер Y перед тем, как он был заперт или что-то еще? –

3

short s обычно два байта и 16 бит. Когда вы говорите:

short s; 
((char*)&s)[0] = 0x00; 
((char*)&s)[1] = 0x1f; 

Это устанавливает первый из этих двух байтов в 0x00 и второй из этих двух байтов в 0x1f. Дело в том, что в C++ не указывается, какая настройка первого или второго байта соответствует значению полного short, поэтому разные платформы могут делать разные вещи. В частности, некоторые платформы говорят, что установка первого байта влияет на «самые важные» биты 16 бит short, а установка второго байта влияет на «наименее значимые» биты 16 бит short. Другие платформы говорят наоборот; Эта настройка первого байта влияет на младшие значащие биты, а установка второго байта влияет на наиболее значимые биты. Эти два поведения платформы называются big-endian и little-endian соответственно.


Решение, чтобы получить последовательное поведение независимо от этих различий не доступ к байт short таким образом. Вместо этого вы должны просто манипулировать значением short, используя методы, которые определяют , например, с побитовыми и арифметическими операторами.

short s; 
s = (0x1f << 8) | (0x00 << 0); // set the most significant bits to 0x1f and the least significant bits to 0x00. 

Проблема заключается в том, что, по многим причинам, я могу только изменить тело функции F2. Я не могу изменить его прототип. Есть ли способ найти размер Y перед тем, как он был заперт или что-то еще?

Вы не можете определить оригинальный тип и размер, используя только char*. Вы должны знать правильный тип и размер с помощью других средств. Если F2 никогда не вызывается, кроме как с CustomStruct, то вы можете просто бросить char* обратно CustomStruct так:

void F2(char* Y) 
{ 
    CustomStruct *X = (CustomStruct*)Y; 
    X->Element[0] = 0x1F00; 
} 

Но помните, что такие забросы не являются безопасными в целом; вы должны только вернуть указатель к тому, из чего он был изначально выбран.

+0

Большое вам спасибо. Проблема в том, что по многим причинам я могу только изменить тело функции F2. Я не могу изменить его прототип. Есть ли способ найти размер Y перед тем, как он был заперт или что-то еще? –

Смежные вопросы