c Расширенные общие вопросы письменного теста
- В чем разница между перечислением и макросом #define?
Обзор перечисления и макросов
(1) Перечисление: относится к перечислению значений переменных по одному, при этом значение переменной ограничено диапазоном перечисленных значений
(2) #define определение макроса заключается в использовании указанного идентификатора Представляет строку
Разница между перечислением и макросом
#define (1) Переменные перечисления могут быть отлажены в компиляторе, но макроконстанты не могут быть отлажены
(2) Макроконстанты #define просто заменяются на этапе предварительной компиляции. Константы перечисления определяются во время компиляции.
(3) Перечисления могут определять большое количество связанных констант одновременно, а макрос #define может определять только одну за раз
- Сколько памяти занимает пустая структура?
Размер памяти,
занимаемой структурой, представляет собой сумму памяти, занятой ее членами. Память, занимаемая пустой структурой, составляет 1 байт.
Поскольку компилятор считает, что любой тип данных имеет свой собственный размер, он может быть
выделен, только если переменная определена с этим типом. Правильный размер области памяти, char занимает наименьшую память из всех типов данных, которая составляет 1 байт.
- Преимущества перечисленных типов
(1) Константа перечисления эквивалентна символьной константе, поэтому ее преимущество состоит в том, что она известна по имени и может повысить удобочитаемость программы.
(2) Диапазон значений переменной типа перечисления ограничен перечисленным диапазоном констант перечисления. Если значение не находится в указанном диапазоне, система будет рассматривать это как ошибку, что может помочь системе проверить ошибку и уменьшить сложность понимания программы.
(3) Тип перечисления также облегчает системе выполнение проверки типа для переменных перечисления, тем самым повышая безопасность
- В чем сходство и различие между макросами typedef и #define?
(1) Сходство
обычно можно понимать как псевдоним для символа, и новый символ используется для замены исходного символа в программе.
(2) Разница
а. Существенное значение отличается. #Define - это замена строки, а typedef - У типа есть псевдоним
. B. В конце определения макроса нет точки с запятой в качестве знака конца, и это не делается в процессе компиляции, но было завершено в процессе предварительной обработки. Трудно найти потенциальные ошибки
#define INT int*
typedef int* my_intp;
INT i, i_p; ==> int* i, i_p;
my_intp a, ap;
-
Какое влияние оказывают режимы с прямым и обратным порядком байтов на данные типа объединения
Режим
прямого порядка байтов (1) Хранение в режиме прямого порядка байтов: данные высокого порядка хранятся в нижнем адресе
(2) Хранение в режиме прямого порядка байтов: данные высокого порядка хранятся в верхнем адресе Влияние режима
прямого порядка байтов на данные типа объединения
Память, занятая данными типа объединения Равно памяти, занимаемой его самым большим членом, доступ к элементам типа объединения начинается со смещения 0 относительно базового адреса объединения, что означает, что доступ к объединению независимо от того, к какой переменной осуществляется доступ Все начинаются с первого адреса объединения, поэтому хранение большого и малого режима напрямую влияет на значение члена объединения. -
Как доказать, что все члены переменной union имеют общий блок памяти?
Объявите, что тип union имеет две переменные-члены, одна из которых является массивом типа int, а другая - массивом типа char. Сначала присвойте значение в соответствии с одним из элементов массива типа int, а затем выводите в соответствии с другим элементом массива типа char. Если массив целых чисел и массив символов совместно используют одну и ту же память, выходной и записанный контент должны быть согласованными, в противном случае результаты будут несовместимыми.
- Проблема с выравниванием байтов
Что такое байтовое выравнивание?
Базовая единица размера памяти в компьютере - байт. Теоретически к определенному базовому типу данных можно получить доступ с любого адреса, но на самом деле компьютер не читает и не записывает память побайтно, а использует 2, 4, Или байтовые блоки, кратные 8, для чтения и записи в память, так что будут некоторые ограничения на юридический адрес основного типа данных, то есть его адрес должен быть кратным 2, 4 или 8. Затем различные типы данных необходимо расположить в пространстве по определенным правилам, то есть выравниванию. === «Обычно 32-битные системы или микроконтроллеры выравниваются по 4 байтам.
Каковы правила выравнивания?
- Первый адрес структурной переменной может быть равномерно разделен по размеру его байта выравнивания.
- Смещение каждого члена структуры относительно первого адреса структуры является целым числом, кратным размеру члена. Если оно не удовлетворяется, предыдущий член заполняется байтами, чтобы удовлетворить его.
- Общий размер структуры является целым числом, кратным размеру байтов выравнивания структуры. Если он не удовлетворен, байты окончательно заполняются, чтобы удовлетворить его.
#include<stdio.h>
#include<stdint.h>
struct test
{
int a;
char b;
int c;
short d;
};
int main(int argc,char *argv)
{
printf("the size of struct test is %d\n",sizeof(struct test));
return 0;
}
результат операции:
the size of struct test is 16
Другой метод определения
#include<stdio.h>
#include<stdint.h>
struct test
{
int a;
int c;
char b;
short d;
};
int main(int argc,char *argv)
{
printf("the size of struct test is %d\n",sizeof(struct test));
return 0;
}
результат операции:
the size of struct test is 12
Вывод: при проектировании конструкции разумная регулировка положения элементов может значительно сэкономить место для хранения
Почему с байтовым выравниванием?
Повышение производительности системы памяти
Кросс-платформенное программирование
Вы можете использовать #pragma pack (n), чтобы выровнять структуры по одному байту.
#pragma pack(1) /*1字节对齐*/
struct test
{
int a;
char b;
int c;
short d;
};
подводить итоги:
- Элементы конструкции разумно расположены для экономии места
- Межплатформенная структура данных может учитывать выравнивание по 1 байту, что экономит место, но влияет на эффективность доступа
- Кросс-платформенная структура данных искусственно заполняется байтами для повышения эффективности доступа, но не экономит место
- Для локальных данных используется выравнивание по умолчанию для повышения эффективности доступа
- В следующем make-файле, каков результат печати терминала после выполнения make.
all:cd ef
@echo 123
cd:
@echo 456
ef:
@echo 789
Ответ:
456
789
123
-
В следующем make-файле, каков результат печати терминала после выполнения make.
Makefile
x := foo y := $(x)b x := new .PHONY : test test : @echo "x => $(x)" @echo "y => $(y)"
результат:
x => new y => foob
Makefile
x = foo y = $(x)b x = new a = $(b) b = $(c) c = hello-makefile .PHONY : test test : @echo "x => $(x)" @echo "y => $(y)" @echo "a => $(a)" @echo "b => $(b)" @echo "c => $(c)"
результат:
x => new y => newb a => hello-makefile b => hello-makefile c => hello-makefile
Makefile
x := foo y := $(x)b x ?= new .PHONY : test test : @echo "x => $(x)" @echo "y => $(y)"
результат:
x => foo y => foob
Makefile
x := foo y := $(x)b x += new .PHONY : test test : @echo "x => $(x)" @echo "y => $(y)"
результат:
x => foo new y => foob
подводить итоги:
Простое присвоение (: =)
Рекурсивное присваивание (=)
Условное присвоение (? =)
Добавить присвоение (+ =)
-
В следующем файле Makefile результат отображения терминала после выполнения make:
Makefile
.PHONY : all first second third all : first second third @echo "\$$@ => $@" @echo "$$^ => $^" @echo "$$< => $<"
результат:
$@ => all $^ => first second third $< => first
подводить итоги:
& @ Цель, которая запускает команду для выполнения в текущем правиле
& ^ Все зависимости в текущем правиле
& <Первая зависимость в текущем правиле
применение:
CC := gcc TARGET := hello-world.out $(TARGET) : func.o main.o $(CC) -o $@ $^ func.o : func.c $(CC) -o $@ -c $^ main.o : main.c $(CC) -o $@ -c $^ .PHONY : rebuild clean all rebuild : clean all all : $(TARGET) clean : rm *.o $(TARGET)