2016-12-16 7 views
1

Question имеет отношение к делу.memset операция по двойной стрелке

Для представления ниже,

typedef struct List{ 

    void **array; // array of void* 
    int lastItemPosition; 
    int size; 
    }List; 

    #define INITIAL_LIST_SIZE 50 

createList выполняет, как показано ниже,

List *createList(List *list, Op opType){ 

    List *lptr = (List *)malloc(sizeof(List)); 

    if(opType == CREATE_NEW_LIST){ 

    lptr->array = malloc(INITIAL_LIST_SIZE*sizeof(void*)); 
    lptr->array = memset(lptr->array, NULL, INITIAL_LIST_SIZE*sizeof(void *)); 
    lptr->lastItemPosition = -1; 
    lptr->size = INITIAL_LIST_SIZE; 
} 

ли memset выполнения допустимую операцию на lptr->array?

+0

[Пожалуйста, просмотрите эту дискуссию о том, почему бы не использовать возвращаемое значение 'malloc()' и family в 'C'.] (Http://stackoverflow.com/q/605845/2173917). –

ответ

2

В коде

memset(lptr->array, NULL, INITIAL_LIST_SIZE*sizeof(void *)); 

является неправильным, так как второй аргумент, как ожидается, быть int, вы передаете указатель. Преобразование является строго определенным поведением, и в большинстве случаев он будет вызывать UB.

Связанные со ссылкой на C11, глава §7.19

NULL
который расширяется к реализации определенных нулевой константы указателя; [...]

и, глава §6.3.2.3

Целое константа со значением 0, или такое выражение преобразованный к типу void *, называется null pointer constant.

Так, NULL имеет тип указателя, который не является совместимым с типом int в любых направлениях.

+0

'#define NULL 0' в' stddef.h' – overexchange

+0

@overexchange показать мне то же самое в главе 7.19, C11. –

+0

'NULL' требуется только для нулевого значения.Тем не менее, он может иметь тип указателя, и в этом случае передача его, где ожидается «int», является недопустимой (и не будет компилироваться). – Peter

1

Это действует на всех основных платформах, за исключением одного: не передавать NULL в качестве значения для установки. Помните, что функция memset работает с отдельным байтами памяти, и вы должны установить все байты в ноль (0).

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


И если кому-то интересно узнать, даже если NULL определяется как 0 (или ((void *) 0)) не имеет значения. Компилятор переведет этот нуль в определенную платформой версию нулевого указателя, которая может быть чем-то иным, чем фактическое целое число.

+0

Я сохранил 'NULL' для удобочитаемости, говоря, что каждый' void * 'в' ** array' равен 'NULL' – overexchange

+0

@overexchange Это может заставить компилятор выпустить предупреждение о конверсиях из указателя в тип без указателя, в зависимости от определение 'NULL'. –

+0

Можете ли вы перечислить любой случай, когда NULL! = 0? Насколько я понимаю, NULL не определяется стандартом, но NULL == 0 настолько вездесущ, что это может быть и так. – doron