MatrixManAtYrService MatrixManAtYrService - 16 days ago 5
C++ Question

Why is my pipe inserting an extra space between writes?

I have the following simple program. It echos lines until it receives one with a lone

q
. Then it quits.

// quitOnQ.cpp
int main()
{
string line;
while (line != "q")
{
cout << line << endl;
getline(cin, line);
}
return 0
}


When I launch the program on its own, it works as expected. However, if I launch it from another program and use an anonymous pipe to write to stdin twice, I get an extra space prefixed to the contents of the second write.




Manual Run



j<enter>
-> "j"

q<enter>
-> [program closes]

Piped stdin A (success)



q\n
-> [program closes]

Piped stdin B (success)



j\nq\n
-> [program closes]

Piped stdin C (failure)



j\n
-> "j"

q\n
-> " q" [program remains open, notice the extra space]




Why does this happen?

Here is the code I am using to write to stdin:

#include <Windows.h>
#include <iostream>
#include <thread>

int main()
{
HANDLE hWriteIN, hReadIN;
SECURITY_ATTRIBUTES saPipe;
PROCESS_INFORMATION procInfo;
STARTUPINFO procSi;
DWORD dwWritten, dwRead;

saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
saPipe.bInheritHandle = TRUE;
saPipe.lpSecurityDescriptor = NULL;

// child stdin pipe
CreatePipe(&hReadIN, &hWriteIN, &saPipe, 0);
SetHandleInformation(hWriteIN, HANDLE_FLAG_INHERIT, 0);

ZeroMemory(&procInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&procSi, sizeof(STARTUPINFO));
procSi.cb = sizeof(STARTUPINFO);
procSi.hStdInput = hReadIN;
procSi.dwFlags |= STARTF_USESTDHANDLES;

TCHAR args[] = TEXT("quitOnQ.exe");
CreateProcess(NULL, args, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &procSi, &procInfo);

this_thread::sleep_for(5s);

WriteFile(hWriteIN, "j\n", sizeof("j\n"), &dwWritten, NULL);
WriteFile(hWriteIN, "q\n", sizeof("q\n"), &dwWritten, NULL);
//WriteFile(hWriteIN, "j\nq\n", sizeof("j\nq\n"), &dwWritten, NULL);

this_thread::sleep_for(5s);

CloseHandle(hWriteIN);

return 0;
}

Answer

The problem is that you are using sizeof() incorrectly. A char string literal is treated as a null-terminated const char[] array by the compiler. Calling sizeof() on a string literal includes the null-terminator in the size! sizeof("j\n") is 3, not 2 like you are expecting. That null terminator is where your extra space is coming from. You should be using strlen() instead:

WriteFile(hWriteIN, "j\n", strlen("j\n"), &dwWritten, NULL);
WriteFile(hWriteIN, "q\n", strlen("q\n"), &dwWritten, NULL);

That being said, you should change your reading loop to this instead:

int main()
{
    string line;
    while (getline(cin, line))
    {
        if (line == "q") break;
        cout << line << endl;
    }  
    return 0
}

And don't forget to close the handles that CreateProcess() returns:

CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
Comments