2016-06-13 1 views
-6

Почему следующий код работает по-разному на IA-32 и x86-64?a - double, printf ("% d", a); работает по-разному в IA32 и IA32-64

#include <stdio.h> 
int main() { 
    double a = 10; 
    printf("a = %d\n", a); 
    return 0; 
} 

На IA-32, результат всегда равен 0. Однако на x86-64 результат может быть что-нибудь между MAX_INT и MIN_INT.

+2

Неопределенное поведение для вызова 'printf' с аргументами, которые не соответствуют строке формата. –

+0

Не моя область, но она похожа на x86-64 аргументы 'double' и' int' передаются в разных регистрах, поэтому 'a' передается' printf() 'в одном месте, но при обработке format string 'printf()' ищет аргумент 'int' в другом регистре, который содержит мусор, поскольку он не использовался для передачи аргумента. – Dmitri

ответ

1

%d на самом деле используется для печати int. Исторически d стоял за «десятичный», чтобы контрастировать с o для восьмеричного и x для шестнадцатеричных.

Для печати double вы должны использовать %e, %f или %g.

Использование неправильного спецификатора формата вызывает undefined behaviour, что означает, что все может произойти, включая неожиданные результаты.

+0

Возможно, вы захотите указать правильные форматы для типа 'double':' '% g" ',' "% f" 'и' '% e" '. –

+0

Я знаю правильный формат для печати дважды. Это вопрос, заданный моим учителем, поэтому я думаю, что за этим стоит что-то таинственное. Благодаря! –

+0

@MartinGao не забудьте заручиться этим веб-сайтом с ответом, когда вы включите свое задание. –

0

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

Что касается того, почему вы видите разницу между x86 (32-разрядной) и x86-64, это, вероятно, связано с различиями в способе передачи параметров в каждом случае.

В случае x86, аргументы printf(), вероятно, передается на стек, выровнены по границам 4-байтовых - поэтому, когда printf() обрабатывает %d спецификатор считывает 4 байта int из стека, которая на самом деле нижние 4 байта от a. Поскольку a было 10 эти байты не не бит установлен, поэтому они интерпретируются как int значение 0.

В x86-64 случае аргументы printf() все передаются в регистрах (хотя некоторые бы на стек, если их было достаточно) ... но double аргументы передаются в разных регистрах, чем int аргументы (например,% xmm0 вместо% rsi). Поэтому, когда printf() пытается обработать аргумент int для соответствия спецификатору %d, он принимает его из другого регистра, который был передан одним a, и использует все остальное значение мусора в регистре, а не нижние байты a, и интерпретирует это как какой-то фигня int значение.

+0

В случае x86, в соответствии с IEEE754, я знаю, почему это всегда 0. Но я мало знаю об отправке аргументов в x86-64-случае. Я смотрю на код asm, используя gdb и обнаруживаю, что он проходит ** ** через **% xmm0 **, поэтому я считаю, что вы правы. –

+0

Интересным следствием этого же эффекта является то, что вы иногда можете передавать целые и с плавающей запятой аргументы в неправильном порядке и по-прежнему получать нормальное поведение. С 64-битной в моей системе я получаю одинаковые результаты между 'printf ("% d,% f \ n ", 1234,10.7);' и 'printf ("% d,% f \ n ", 10.7, 1234) ; 'потому что' 1234' является первым 'int' (после строки формата), а' 10.7' является первым 'double', независимо от того, в каком порядке они передаются. – Dmitri

+0

Я получаю те же результаты в своей системе. Вы полностью решили мою проблему и рассказали мне, что на самом деле происходит в этом неопределенном поведении ~ Спасибо ~ –

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