I am trying to send an integer with pipe in a POSIX system but write() function is working for sending string or character data. Is there any way to send integer with a pipe?
Regards
The safe way is to use snprintf and strtol.
But if you know both processes were created using the same version of compiler (for example, they're the same executable which forked), you can take advantage of the fact that anything in C can be read or written as an array of char:
int n = something();
write(pipe_w, &n, sizeof(n));
int n;
read(pipe_r, &n, sizeof(n));
Either send a string containing the ASCII representation of integer e.g., 12345679, or send four bytes containing the binary representation of int, e.g., 0x00, 0xbc, 0x61, 0x4f.
In the first case, you will use a function such as atoi() to get the integer back.
Aschelpler's answer is right, but if this is something that can grow later I recommend you use some kind of simple protocol library like Google's Protocol Buffers or just JSON or XML with some basic schema.
Below one works fine for writing to pipe and reading from pipe as:
stop_daemon =123;
res = write(cli_pipe_fd_wr, &stop_daemon, sizeof(stop_daemon));
....
res = read(pipe_fd_rd, buffer, sizeof(int));
memcpy(&stop_daemon,buffer,sizeof(int));
printf("CLI process read from res:%d status:%d\n", res, stop_daemon);
output:
CLI process read from res:4 status:123
Related
I'm a noob on C and trying to use write() function to show an integer.
These is my code:
int n = 7;
write(1, &n, 4);
I want to show 7, but the program shows nothing or other strange character when I set n to a big number.
What am I missing?
Objects like int are represented in memory with various bits. The write routine transmits exactly those bits of memory to its destination.
Terminals are not designed to display arbitrary bits of memory. They do not interpret the bits to mean an int or other object and then display that interpretation. Generally, we transmit characters to terminals. More specifically, we send codes that represent characters. Terminals are designed to receive these codes and display little pictures of writing (characters, glyphs, emoji, whatever).
To make a terminal display “7”, we need to send it the code for “7”. A common code system for characters is ASCII (American Standard Code for Information Interchange). The ASCII code for “7” is 55. So, if you do this:
char x = 55;
write(1, &x, 1);
then the terminal will draw “7” on its display, if ASCII is being used.
So write is the wrong routine to use to display int values for a human to read. Instead, you normally use printf, like this:
printf("%d", n);
The f in printf stands for formatted. It examines the bits that represent the value in n and formats the represented value as characters intended for humans to read, and then it writes those characters to standard output.
If you want to use write to transmit characters to the terminal, you can use sprintf to get just the formatting part of printf without the printing part. For starters, this code will work:
char buffer[80]; // Make space for sprintf to work in.
int LengthUsed = sprintf(buffer, "%d", n); // Format n in decimal.
write(1, buffer, LengthUsed); // Write the characters.
(More sophisticated code would adapt the buffer size to what is needed for the sprintf.)
void ft_putnbr_fd(int nu, int fd)
{
long int n;
n = nu;
if (n < 0)
{
ft_putchar_fd('-', fd);
n = n * (-1);
}
if (n < 10)
{
ft_putchar_fd(n + '0', fd);
}
else
{
ft_putnbr_fd(n / 10, fd);
ft_putchar_fd(n % 10 + '0', fd);
}
}
When you want to print it out on the command prompt only use printf() instead:
int n = 7;
printf("%i",n);
Is there a special intention for using the write() function?
If so, please add more of your code.
When you say something like
int n = 7;
write(fd, &n, sizeof(int));
you are taking the individual bytes corresponding to the integer n and writing them out to the file descriptor fd.
And that works just fine, unless what you wanted was a human readable representation of the integer n. That's the representation you'd get if you had instead written
printf("%d\n", n);
It's printf's job, when you use a format specifier like %d, to create a human-readable string of characters corresponding to a data object.
So if you want to print an int in a human-readable way, printf is definitely your best bet. If for some reason you can't use printf, you can use sprintf to create an in-memory string, then use write to write that out:
char tmpbuf[30];
sprintf(tmpbuf, "%d", n);
write(fd, tmpbuf, strlen(tmpbuf));
If for some reason you can't use sprintf, you might be able to use itoa:
char tmpbuf[30];
itoa(n, tmpbuf, 10);
write(fd, tmpbuf, strlen(tmpbuf));
However, the itoa function is not standard. If you don't have it or can't use it, your last resort would be to convert an integer to its string representation yourself, by hand. That's such a common question that I'm not going to provide Yet Another answer to it here, but see the linked question, or this one.
You didn't ask, but if there's ever the related problem of printing a floating point number using write, there are some hints in the comments at this question.
Write function is a system call. It is used to write the content of a buffer to a declared output or to a stream. You should not use write.
Instead, you must be using printf(" ", ...). In your case:
printf("%d", n);
or
print("%d\n",n);
if you want to write it on a line and do an end line(jump the next).
For more information about printf see: printf
I don't understand why I'm able to read() every character I type on my terminal but if I try to assign a non ascii value to a C variable it doesn't work.
There are three main questions below this code ->
int main (){
int fd;
fd = open("./dog.txt",O_RDONLY);
//contents of dog.txt -> 漢è hello
ssize_t r;
char b;
while( (r = read( fd, &b, sizeof(b))) > 0 ){
write(STDOUT_FILENO,&b, sizeof(b));
}
printf("\n");
//OUTPUT : 漢è hello
}
However something like this is not accepted :
int main (){
unsigned int test = '漢';
write(STDOUT_FILENO,&test,sizeof(test));
printf("\n");
}
The c program receives a series of bytes one at a time and then it sends them back one at a time to the terminal through the write system call ( the buffer in the example is 1 Byte ).
But how does the terminal know that it must "interpret" the chinese character as a group of 3 Bytes when I write()? Considering that I'm writing 1 Byte at a time it could have well interpreted each single Byte as three different 8 Bytes characters.
Is there some sort of cooperation between the process and the terminal to make this possible?
Could someone provide a straight to the point explanation of character encodings in both terminal and programs (in this case C)?
But how does the terminal know that it must "interpret" the chinese character as a group of 3 Bytes when I write() ? ...
The terminal sees a stream of bytes and tries to decode that stream into characters irrespectively of whether they were written with one write call or multiple calls.
The exact way it decodes the stream depends on the encoding used in your system. I assume that your system uses UTF-8, because that's an encoding where 漢 is represented with the sequence of the three bytes e6 bc a2 (here in hexadecimal). In UTF-8, the number of bytes the character takes is determined by its first byte. UTF-8 is actually ingenious for that and a few other reasons. For details you should refer the Wikipedia page on UTF-8.
Is there some sort of cooperation between the process and the terminal to make this possible ?
The process and the terminal both follow the system convention about which encoding to use. On UNIX systems that's determined by the value of the LANG, LC_ALL (or some other) environment variables. This might be seen as 'cooperation', but there's definitively no two-way communication between them other than the respective byte streams.
However something like this is not accepted : ...
It actually may work on some implementations. However the exact meaning of character literals (single-quoted strings) with multi-byte characters or multiple characters is not defined per the standard.
What is going to work on most UNIX systems though, is using a string literal and saving the source file in UTF-8:
char test[] = "漢";
write(STDOUT_FILENO, test, strlen(test));
printf("\n");
I'm a noob on C and trying to use write() function to show an integer.
These is my code:
int n = 7;
write(1, &n, 4);
I want to show 7, but the program shows nothing or other strange character when I set n to a big number.
What am I missing?
Objects like int are represented in memory with various bits. The write routine transmits exactly those bits of memory to its destination.
Terminals are not designed to display arbitrary bits of memory. They do not interpret the bits to mean an int or other object and then display that interpretation. Generally, we transmit characters to terminals. More specifically, we send codes that represent characters. Terminals are designed to receive these codes and display little pictures of writing (characters, glyphs, emoji, whatever).
To make a terminal display “7”, we need to send it the code for “7”. A common code system for characters is ASCII (American Standard Code for Information Interchange). The ASCII code for “7” is 55. So, if you do this:
char x = 55;
write(1, &x, 1);
then the terminal will draw “7” on its display, if ASCII is being used.
So write is the wrong routine to use to display int values for a human to read. Instead, you normally use printf, like this:
printf("%d", n);
The f in printf stands for formatted. It examines the bits that represent the value in n and formats the represented value as characters intended for humans to read, and then it writes those characters to standard output.
If you want to use write to transmit characters to the terminal, you can use sprintf to get just the formatting part of printf without the printing part. For starters, this code will work:
char buffer[80]; // Make space for sprintf to work in.
int LengthUsed = sprintf(buffer, "%d", n); // Format n in decimal.
write(1, buffer, LengthUsed); // Write the characters.
(More sophisticated code would adapt the buffer size to what is needed for the sprintf.)
void ft_putnbr_fd(int nu, int fd)
{
long int n;
n = nu;
if (n < 0)
{
ft_putchar_fd('-', fd);
n = n * (-1);
}
if (n < 10)
{
ft_putchar_fd(n + '0', fd);
}
else
{
ft_putnbr_fd(n / 10, fd);
ft_putchar_fd(n % 10 + '0', fd);
}
}
When you want to print it out on the command prompt only use printf() instead:
int n = 7;
printf("%i",n);
Is there a special intention for using the write() function?
If so, please add more of your code.
When you say something like
int n = 7;
write(fd, &n, sizeof(int));
you are taking the individual bytes corresponding to the integer n and writing them out to the file descriptor fd.
And that works just fine, unless what you wanted was a human readable representation of the integer n. That's the representation you'd get if you had instead written
printf("%d\n", n);
It's printf's job, when you use a format specifier like %d, to create a human-readable string of characters corresponding to a data object.
So if you want to print an int in a human-readable way, printf is definitely your best bet. If for some reason you can't use printf, you can use sprintf to create an in-memory string, then use write to write that out:
char tmpbuf[30];
sprintf(tmpbuf, "%d", n);
write(fd, tmpbuf, strlen(tmpbuf));
If for some reason you can't use sprintf, you might be able to use itoa:
char tmpbuf[30];
itoa(n, tmpbuf, 10);
write(fd, tmpbuf, strlen(tmpbuf));
However, the itoa function is not standard. If you don't have it or can't use it, your last resort would be to convert an integer to its string representation yourself, by hand. That's such a common question that I'm not going to provide Yet Another answer to it here, but see the linked question, or this one.
You didn't ask, but if there's ever the related problem of printing a floating point number using write, there are some hints in the comments at this question.
Write function is a system call. It is used to write the content of a buffer to a declared output or to a stream. You should not use write.
Instead, you must be using printf(" ", ...). In your case:
printf("%d", n);
or
print("%d\n",n);
if you want to write it on a line and do an end line(jump the next).
For more information about printf see: printf
I am trying to write out the size in bytes of a string that is defined as
#define PATHA "/tmp/matrix_a"
using the code
rtn=write(data,(strlen(PATHA)*sizeof(char)),sizeof(int));
if(rtn < 0)
perror("Writing data_file 2 ");
I get back Writing data_file 2 : Bad address
What exactly about this is a bad address? The data file descriptor is open, and writes correctly immediately before and after the above code segment. The data to be written to the file data needs to be raw, and not ASCII.
I have also tried defining the string as a char[] with the same issue
The second argument to write() is the address of the bytes you want to write, but you are passing the bytes you want to write themselves. In order to get an address, you must store those bytes in a variable (you can't take the address of the result of an expression). For example:
size_t patha_len = strlen(PATHA);
rtn = write(data, &patha_len, sizeof patha_len);
The arguments to POSIX write() are:
#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t nbyte);
That's a:
file descriptor
buffer
size
You've passed two sizes instead of an address and a size.
Use:
rtn = write(data, PATHA, sizeof(PATHA)-1);
or:
rtn = write(data, PATHA, strlen(PATHA));
If you are seeking to write the size of the string as an int, then you need an int variable to pass to write(), like this:
int len = strlen(PATHA);
rtn = write(data, &len, sizeof(len));
Note that you can't just use a size_t variable unless you want to write a size_t; on 64-bit Unix systems, in particular, sizeof(size_t) != sizeof(int) in general, and you need to decide which size it is you want to write.
You also need to be aware that some systems are little-endian and others big-endian, and what you write using this mechanism on one type is not going to be readable on the other type (without mapping work done before or after I/O operations). You might choose to ignore this as a problem, or you might decide to use a portable format (usually, that's called 'network order', and is equivalent to big-endian), or you might decide to define that your code uses the opposite order. You can write the code so that the same logic is used on all platforms if you're careful (and all platforms get the same answers).
The second argument to write() is the buffer and third argument is the size:
ssize_t write(int fd, const void *buf, size_t count);
The posted code passes the length which is interpreted as an address which is incorrect. The compiler should have emitted a warning about this (don't ignore compiler warnings and compile with the warning level at the highest level).
Change to:
rtn=write(data, PATHA, strlen(PATHA));
Note sizeof(char) is guaranteed to be 1 so it can be omitted from the size calculation.
The Bad address error has already been answered. If you want to write the size of a string just use printf.
printf("Length: %d\n", strlen(data));
Either that, or you can write a function that will convert an integer to a string and print that out... I prefer printf :)
rtn = write(data, PATHA, strlen(PATHA));
is what you want I think. Arguments are supposed to be
file descriptor (data)
the source buffer (your string constant PATHA)
The number of bytes to pull from that buffer (measured using strlen() on the same PATHA constant)
Also, to be complete, you should always check rtn for how many characters you've written. You're not guaranteed that you write() all the bytes requested on all descriptor types. So sometimes you end up writing it in chunks, determined by the amount it answers that it wrote, vs how many you know you have yet to write still then.
I'm lead to believe that write() can only send data buffers of byte (i.e. signed char), so how do I send an array of long integers using the C write() function in the sys/socket.h library?
Obviously I can't just cast or convert long to char, as any numbers over 127 would be malformed.
I took a look at the question, how to decompose integer array to a byte array (pixel codings), but couldn't understand it - please could someone dumb it down a little if this is what I'm looking for?
Follow up question:
Why do I get weird results when reading an array of integers from a TCP socket?
the prototype for write is:
ssize_t write(int fd, const void *buf, size_t count);
so while it writes in units of bytes, it can take a pointer of any type. Passing an int* will be no problem at all.
EDIT:
I would however, recomend that you also send the amount of integers you plan to send first so the reciever knows how much to read. Something like this (error checking omitted for brevity):
int x[10] = { ... };
int count = 10;
write(sock, &count, sizeof(count));
write(sock, x, sizeof(x));
NOTE: if the array is from dynamic memory (like you malloced it), you cannot use sizeof on it. In this case count would be equal to: sizeof(int) * element_count
EDIT:
As Brian Mitchell noted, you will likely need to be careful of endian issues as well. This is the case when sending any multibyte value (as in the count I recommended as well as each element of the array). This is done with the: htons/htonl and ntohs/ntohl functions.
Write can do what you want it to, but there's some things to be aware of:
1: You may get a partial write that's not on an int boundary, so you have to be prepared to handle that situation
2: If the code needs to be portable, you should convert your array to a specific endianess, or encode the endianess in the message.
The simplest way to send a single int (assuming 4-byte ints) is :
int tmp = htonl(myInt);
write(socket, &tmp, 4);
where htonl is a function that converts the int to network byte order. (Similarly,. when you read from the socket, the function ntohl can be used to convert back to host byte order.)
For an array of ints, you would first want to send the count of array members as an int (in network byte order), then send the int values.
Yes, you can just cast a pointer to your buffer to a pointer to char, and call write() with that. Casting a pointer to a different type in C doesn't affect the contents of the memory being pointed to -- all it does is indicate the programmer's intention that the contents of memory at that address be interpreted in a different way.
Just make sure that you supply write() with the correct size in bytes of your array -- that would be the number of elements times sizeof (long) in your case.
It would be better to have serialize/de-serialize functionality in your client /server program.
Whenever you want to send data, serialize the data into a byte buffer and send it over TCP with byte count.
When receiving data, de-serialize the data from buffer to your own interpretation .
You can interpret byte buffer in any form as you like. It can contain basic data type, objects etc.
Just make sure to take care of endianess and also alignment stuff.
Declare a character array. In each location of the array, store integer numbers, not characters.
Then you just send that.
For example:
char tcp[100];
tcp[0] = 0;
tcp[1] = 0xA;
tcp[2] = 0xB;
tcp[3] = 0xC;
.
.
// Send the character array
write(sock, tcp, sizeof(tcp));
I think what you need to come up with here is a protocol.
Suppose your integer array is:
100, 99, 98, 97
Instead of writing the ints directly to the buffer, I would "serialize" the array by turning it into a string representation. The string might be:
"100,99,98,97"
That's what would be sent over the wire. On the receiving end, you'd split the string by the commas and build the array back up.
This is more standardised, is human readable, and means people don't have to think about hi/lo byte orders and other silly things.
// Sarcasm
If you were working in .NET or Java, you'd probably encode it in XML, like this:
<ArrayOfInt><Int>100</Int><Int>99</Int><Int>98</Int><Int>97</Int></ArrayOfInt>
:)