Блок кода, который должен вызвать ошибку шины, выполняется нормально - PullRequest
0 голосов
/ 24 декабря 2018

В настоящее время я читаю Программирование на C - Секреты Deep C.На странице 164, где автор объяснял ошибку шины и ошибку сегментации, он показал эту строку кода

union { 
  char a[10];
  int i;
} u ;

int * p = ( int * ) &(u.a[1]);
*p = 17; /* the misaligned addr in p causes a bus error */

Предполагается, что приведенный выше код вызывает ошибку шины, но когда я ее запускал, он работал нормально безлюбая ошибкаАвтор дал следующее объяснение

Это вызывает ошибку шины, потому что объединение массив / int гарантирует, что массив символов «а» также находится по разумно выровненному адресу для целого числа, поэтому «а + 1»определенно нет.Затем мы пытаемся сохранить 4 байта в адресе, который выровнен только для однобайтового доступа.Хороший компилятор предупредит о смещении, но не сможет определить все вхождения.

Мое понимание вышеприведенного утверждения таково, что char равен 1 байту, и мы пытаемся разместить int, которыйравен 4 байта при индексе char a[10], следовательно, возникнет ошибка шины (я не уверен, правильно ли я понимаю или нет)

Мой вопрос: почему приведенный выше код не вызывает ошибку шины.

Примечание: Я не студент CS, простые объяснения помогут.

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

Ответы [ 3 ]

0 голосов
/ 24 декабря 2018

Мое понимание вышеприведенного утверждения состоит в том, что char равен 1 байту, и мы пытаемся поместить int, который составляет 4 байта, в индекс char a [10], следовательно, произойдет ошибка шины (я не уверенесли мое понимание правильное или неправильное)

Проблема не в размере char или int, а в их выравнивании.Как правило, архитектуры очень требовательны к адресам, с которых вы загружаете данные / код, например, вы можете загружать только 16-битное целое число с адреса, кратного 16-битному, или функция всегда должна начинаться с 4-байтовогоborder.

Если вы этого не заметите, процессор может прочитать неверные данные или наказать вас исключением.Затем ОС может эмулировать его, используя несколько выровненных обращений, или передать его как SIGBUS пользовательскому приложению.Последнее является тем, что автор, вероятно, испытывает на своей установке.

Как все это относится к C?

То, что у вас есть, - неопределенное поведение.Взаимодействие процессора, контроллера памяти, компилятора, ОС и носовых демонических появлений в вашем районе будет влиять на то, как это повлияет (если вообще будет).На вашем компьютере возможно, что процессор изначально поддерживает невыровненный доступ, поэтому он работал, но все же это то, на что вы не можете положиться: просто undefined .(Особенно с оптимизацией, эти вещи могут вернуться, чтобы укусить вас. Работы для меня ™ не достаточно хороши, чтобы писать четко определенный C-код!)

0 голосов
/ 24 декабря 2018

Данные, которые вы пытаетесь извлечь, пересекают 32-битную границу, поэтому требуются 2 выборки из памяти (но компилятор не обязательно знает об этом во время компиляции).

Примечание. Книга очень старая иречь идет о 32-битных процессорах.Для 64-битной системы вам, возможно, придется изменить int * p = ( int * ) &(u.a[1]); на int * p = ( int * ) &(u.a[5]);, чтобы все необходимые данные не могли быть получены за одну выборку памяти с выровненного адреса.

По причинам обратной совместимости большинство процессоров Intel (ипроизводные, такие как AMD), автоматически обрабатывают ошибки выравнивания памяти на уровне команд, поэтому вы не заметите ничего плохого (упрощенно автоматически добавляется дополнительное чтение, блокирующее шину, чтобы убедиться, что между чтениями ничего не меняется).

Вклмногие другие архитектуры ЦП (ARM, PowerPC, MIPS, более новые архитектуры Intel) пример кода вызвал бы проблемы, как описано, но теперь некоторые операционные системы, такие как Linux, могут быть настроены на автоматическое обнаружение ошибки и выполнение «исправления», позволяющегоВ программе для неосознанного возникла проблема.В большинстве программ это, вероятно, останется незамеченным для пользователя, но отнимает много времени и может вызвать реальные проблемы с программным обеспечением и драйверами в реальном времени.

Критический по времени код часто условно компилируется, чтобы выполнять или не выполнять не выровненный доступ согласноархитектура процессора, для которой он компилируется.В linux псевдо-файл "/ proc / cpu / alignment" может использоваться для управления поведением ядра и просмотра статистики о количестве исправлений.

0 голосов
/ 24 декабря 2018

Я считаю, что книга ошибочна.Код вызывает неопределенное поведение.Ожидание какого-либо определенного поведения от этого поэтому ошибочно.Также обратите внимание, что не все архитектуры могут вызвать ошибки шины.Если книга не объясняет этот факт, это тоже не говорит об этом.

...