2016-12-13 3 views
4

Я выполнял некоторые тесты в функции вызова c вызовами, и я получаю то, что, по моему мнению, странное поведение при использовании escape-кодов ansi и вызов функции c, использующей printf.Смешивание syscall write with printf on linux

Это сборка часть:

section .data    

    red db 27,"[31;1m",0 
    redlen equ $ - red 

    cyan db 27,"[36;1m",0 
    cyanlen equ $ - cyan 

    colorReset db 27,"[0m",0 
    colorResetLen equ $ - colorReset 

section .text 

extern printLetter 
extern letter 

global main 

main: 
     mov BYTE [letter], 'H' 
     call ansiSetRed 
     call printLetter 
     mov BYTE [letter], 'e' 
     call ansiSetCyan 
     call printLetter 
     mov BYTE [letter], 'l' 
     call ansiReset 
     call printLetter 
     mov BYTE [letter], 'l' 
     call ansiSetRed 
     call printLetter 
     mov BYTE [letter], 'o' 
     call ansiSetCyan 
     call printLetter 
     mov BYTE [letter], '!' 
     call ansiReset 
     call printLetter 
     mov BYTE [letter], 10 
     call printLetter 

     ret 

ansiSetRed: 
     mov rax, 1 
     mov rdi, 1 
     mov rsi, red 
     mov rdx, redlen 
     syscall 
     ret 

ansiSetCyan: 
     mov rax, 1 
     mov rdi, 1 
     mov rsi, cyan 
     mov rdx, cyanlen 
     syscall 
     ret 

ansiReset: 
     mov rax, 1 
     mov rdi, 1 
     mov rsi, colorReset 
     mov rdx, colorResetLen 
     syscall 
     ret  

Выглядит долго, но все, что я действительно это определить некоторые строки с ANSI кодами в начале, один, чтобы установить цвет переднего плана на красный, один для голубого цвета и один для сброса цвета.

Затем у меня есть функции, которые печатают эти строки ansi, используя запись в режиме syscall.

Основная функция состоит в том, чтобы напечатать «Hello!» чередуя цвет каждой буквы, сначала вызывая функцию сборки, которая печатает соответствующую строку ansi, а затем вызывает функцию extern c, которая печатает символ, который хранится в глобальной переменной.

Здесь с частью:

#include <stdio.h> 

char letter; 

void printLetter(void) { 

    printf("%c", letter); 

} 

Когда я запускаю его, сообщение "Hello!" отображаются все белым, как если сборка часть не была печать AnSi кодов

enter image description here

но если изменить гр часть просто напечатать новую строку после каждого символа:

#include <stdio.h> 

char letter; 

void printLetter(void) { 

    printf("%c\n", letter); 

} 

Тогда буквы показывают один из каждого цвета, как я ожидал в начале.

enter image description here

Что может быть причиной такого поведения?

+0

Полезные средства отладки для этого: 'strace' для отслеживания системных вызовов,' ltrace' для отслеживания вызовов функций библиотеки. –

ответ

8

Это потому, что stdio (стандартный пакет ввода-вывода C) использует буферизацию строк для stdout, если stdout отправляется на терминал. Это означает, что данные, которые вы пишете, не сразу отправляются на терминал, а буферизуются до тех пор, пока не будет доступна целая строка. То, что вы наблюдаете в своей первой программе (привет на линии), состоит в том, что ни один из символов Hello на самом деле не написан до тех пор, пока вы не позвоните printLetter с помощью фида строки, в результате чего буфер для stdout будет сброшен на терминал.

Я вижу следующие подходы к решению вашей проблемы (какой-либо одной из них делает трюк, но использовать только один подход):

  • редактировать ansiSetRed т.д. вызвать fwrite вместо непосредственного выполнения write системного вызова в , Это должно сделать работу буферизации, как ожидалось.
  • позвоните setbuf(stdout, NULL), чтобы отключить буферизацию перед записью любых данных.
  • запись в stderr вместо stdout как stderr небуферизован
  • выполнить fflush(stdout) после каждого printf для ручного смыва stdout.
  • Перепишите printLetter, чтобы использовать системный вызов write вместо printf.
+3

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

+2

@MatteoItalia Что все мои предложения делают (отключение буферизации задокументировано в POSIX как поведение, как будто 'fflush' был выполнен после каждой записи, если я правильно помню). – fuz

+2

, конечно, в фактах я подтвердил ваш ответ =) Я просто делал более явный общий момент. –

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