c Расширенные общие вопросы письменного теста

c Расширенные общие вопросы письменного теста

  1. В чем разница между перечислением и макросом #define?

Обзор перечисления и макросов
(1) Перечисление: относится к перечислению значений переменных по одному, при этом значение переменной ограничено диапазоном перечисленных значений
(2) #define определение макроса заключается в использовании указанного идентификатора Представляет строку

Разница между перечислением и макросом
#define (1) Переменные перечисления могут быть отлажены в компиляторе, но макроконстанты не могут быть отлажены
(2) Макроконстанты #define просто заменяются на этапе предварительной компиляции. Константы перечисления определяются во время компиляции.
(3) Перечисления могут определять большое количество связанных констант одновременно, а макрос #define может определять только одну за раз

  1. Сколько памяти занимает пустая структура?

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

  1. Преимущества перечисленных типов

(1) Константа перечисления эквивалентна символьной константе, поэтому ее преимущество состоит в том, что она известна по имени и может повысить удобочитаемость программы.
(2) Диапазон значений переменной типа перечисления ограничен перечисленным диапазоном констант перечисления. Если значение не находится в указанном диапазоне, система будет рассматривать это как ошибку, что может помочь системе проверить ошибку и уменьшить сложность понимания программы.
(3) Тип перечисления также облегчает системе выполнение проверки типа для переменных перечисления, тем самым повышая безопасность

  1. В чем сходство и различие между макросами 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. Какое влияние оказывают режимы с прямым и обратным порядком байтов на данные типа объединения

    Режим
    прямого порядка байтов (1) Хранение в режиме прямого порядка байтов: данные высокого порядка хранятся в нижнем адресе
    (2) Хранение в режиме прямого порядка байтов: данные высокого порядка хранятся в верхнем адресе Влияние режима
    прямого порядка байтов на данные типа объединения
    Память, занятая данными типа объединения Равно памяти, занимаемой его самым большим членом, доступ к элементам типа объединения начинается со смещения 0 относительно базового адреса объединения, что означает, что доступ к объединению независимо от того, к какой переменной осуществляется доступ Все начинаются с первого адреса объединения, поэтому хранение большого и малого режима напрямую влияет на значение члена объединения.

  2. Как доказать, что все члены переменной union имеют общий блок памяти?

Объявите, что тип union имеет две переменные-члены, одна из которых является массивом типа int, а другая - массивом типа char. Сначала присвойте значение в соответствии с одним из элементов массива типа int, а затем выводите в соответствии с другим элементом массива типа char. Если массив целых чисел и массив символов совместно используют одну и ту же память, выходной и записанный контент должны быть согласованными, в противном случае результаты будут несовместимыми.

  1. Проблема с выравниванием байтов

Что такое байтовое выравнивание?

Базовая единица размера памяти в компьютере - байт. Теоретически к определенному базовому типу данных можно получить доступ с любого адреса, но на самом деле компьютер не читает и не записывает память побайтно, а использует 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 байту, что экономит место, но влияет на эффективность доступа
  • Кросс-платформенная структура данных искусственно заполняется байтами для повышения эффективности доступа, но не экономит место
  • Для локальных данных используется выравнивание по умолчанию для повышения эффективности доступа
  1. В следующем make-файле, каков результат печати терминала после выполнения make.
all:cd ef
	@echo 123
cd:
	@echo 456
ef:
	@echo 789

Ответ:

456
789
123
  1. В следующем 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
    
    
    

    подводить итоги:

    Простое присвоение (: =)

    Рекурсивное присваивание (=)

    Условное присвоение (? =)

    Добавить присвоение (+ =)

  2. В следующем файле 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)
    
    	
    
    

рекомендация

отblog.csdn.net/weixin_48430195/article/details/108737875