Recoding printf %p with write function, no printf - c

I am currently working on a task where I need to print the address of a variable. It would be easy to use printf %p but I am only allowed to use write from unistd.
I tried casting the pointer in to an unsigned integer and uintptr_t and then converting it into a hexadecimal number. With uintptr_t it works but with an unsigned integer it only prints half of the address. Maybe someone can explain me why this is the case?
I also saw some solutions using ">>" and "<<" but I didn't get why that works. It would be nice if someone can explain a solution using "<<" and ">>" step by step, because I am not sure if I am allowed to use uintptr_t.
this is the code I use to cast it into a unsigned int / unitptr_t / unsigned long long (I know that ft_rec_hex is missing leading 0's):
void ft_rec_hex(unsigned long long nbr)
{
char tmp;
if (nbr != 0)
{
ft_rec_hex(nbr / 16);
if (nbr % 16 < 10)
tmp = nbr % 16 + '0';
else
tmp = (nbr % 16) - 10 + 'a';
write(1, &tmp, 1);
}
}
int main(void)
{
char c = 'd';
unsigned long long ui = (unsigned long long)&c;
ft_rec_hex(ui);
}

It looks like only half of the address is printed because the "unsigned integer" you used has only half size of uintptr_t. (note that uintptr_t is an unsigned integer type)
You can use an array of unsigned char to store data in a pointer variable and print that to print full pointer withput uintptr_t.
Using character types to read objects with other type is allowed according to strict aliasing rule.
#include <stdio.h>
#include <unistd.h>
void printOne(unsigned char v) {
const char* chars = "0123456789ABCDEF";
char data[2];
data[0] = chars[(v >> 4) & 0xf];
data[1] = chars[v & 0xf];
write(1, data, 2);
}
int main(void) {
int a;
int* p = &a;
/* to make sure the value is correct */
printf("p = %p\n", (void*)p);
fflush(stdout);
unsigned char ptrData[sizeof(int*)];
for(size_t i = 0; i < sizeof(int*); i++) {
ptrData[i] = ((unsigned char*)&p)[i];
}
/* print in reversed order, assuming little endian */
for (size_t i = sizeof(int*); i > 0; i--) {
printOne(ptrData[i - 1]);
}
return 0;
}
Or read data in a pointer variable as unsigned char array without copying:
#include <stdio.h>
#include <unistd.h>
void printOne(unsigned char v) {
const char* chars = "0123456789ABCDEF";
char data[2];
data[0] = chars[(v >> 4) & 0xf];
data[1] = chars[v & 0xf];
write(1, data, 2);
}
int main(void) {
int a;
int* p = &a;
/* to make sure the value is correct */
printf("p = %p\n", (void*)p);
fflush(stdout);
/* print in reversed order, assuming little endian */
for (size_t i = sizeof(int*); i > 0; i--) {
printOne(((unsigned char*)&p)[i - 1]);
}
return 0;
}

It would be easy to use printf %p but I am only allowed to use write from unistd.
Then form a string and print that.
int n = snprintf(NULL, 0, "%p", (void *) p);
char buf[n+1];
snprintf(buf, sizeof buf, "%p", (void *) p);
write(1, buf, n);
Using a pointer converted to an integer marginally reduces portability and does not certainly form the best textual representation of the pointer - something implementation dependent.
With uintptr_t it works but with an unsigned integer it only prints half of the address.
unsigned is not specified to be wide enough to contain all the information in a pointer.
uintptr_t, when available (very common), can preserve most of that information for void pointers. Good enough to round-trip to an equivalent pointer, even if in another form.

Related

Pointer address C without printf

I need to print the address of a pointer (basically recoding %p) but without using printf() and only write() is allowed.
How can I do it? Could you give me some hints?
For example :
printf("%p", a);
result :
0x7ffeecbf6b60`
For your purpose, you just need to convert the pointer value to hex representation and write that to the POSIX file descriptor using the write system call:
#include <stdint.h>
#include <unistd.h>
/* output hex representation of pointer p, assuming 8-bit bytes */
int write_ptr(int hd, void *p) {
uintptr_t x = (uintptr_t)p;
char buf[2 + sizeof(x) * 2];
size_t i;
buf[0] = '0';
buf[1] = 'x';
for (i = 0; i < sizeof(x) * 2; i++) {
buf[i + 2] = "0123456789abcdef"[(x >> ((sizeof(x) * 2 - 1 - i) * 4)) & 0xf];
}
return write(fd, buf, sizeof(buf));
}

C - Pointer points to random values

I'm pretty confused by pointers in general and I have no idea why this is happening. Normally a pointer to an array would just print out the values of an array but I have no idea why this is happening. Could someone explain why or suggest what is happening?
char *showBits(int dec, char *buf) {
char array[33];
buf=array;
unsigned int mask=1u<<31;
int count=0;
while (mask>0) {
if ((dec & mask) == 0) {
array[count]='0';
}
else {
array[count]='1';
}
count++;
mask=mask>>1;
}
return buf;
}
Expecting it to return a binary representation of dec, but printing it produces random garbage.
The problem is that you're returning a reference to local array. Instead, let the caller allocate the buffer. I've also fixed some other problems in the code:
#define MAX_BUFFER_LENGTH (sizeof(unsigned int) * CHAR_BIT + 1)
char *to_bit_string(unsigned int n, char *buf) {
unsigned int mask = UINT_MAX - (UINT_MAX >> 1);
char *tmp;
for (tmp = buf; mask; mask >>= 1, tmp++) {
*tmp = n & mask ? '1': '0';
}
*tmp = 0;
return buf;
}
First of all, we use unsigned int instead of signed int here, because signed ints would be converted to unsigned ints when used in conjunction with unsigned int. Second, unsigned ints can have varying number of bits; so we use sizeof(unsigned int) * CHAR_BIT + 1 to get the absolute maximum of the number of bits. Third, we use UINT_MAX - (UINT_MAX >> 1) as a handy way to get a value that has only the most-significant bit set, no matter how many value bits the number has. Fourth: instead of indices, we use a moving pointer. Fifth - we remember to null-terminate the string.
Usage:
char the_bits[MAX_BUFFER_LENGTH];
puts(to_bit_string(0xDEADBEEF, the_bits));
Output
11011110101011011011111011101111
You have
char *showBits(int dec, char *buf);
and the function is expected "to return a binary representation of dec".
Assuming int is 32 bits, do
#define INT_BITS (32) // to avoid all those magic numbers: 32, 32-1, 32+1
Assuming further that the function is called like this:
int main(void)
{
int i = 42;
char buf[INT_BITS + 1]; // + 1 to be able to store the C-string's '0'-terminator.
printf("%d = 0b%s\n", i, showBits(i, buf));
}
You could change your code as follows:
char *showBits(int dec, char *buf) {
// char array[INT_BITS + 1]; // drop this, not needed as buf provides all we need
// buf=array; // drop this; see above
unsigned int mask = (1u << (INT_BITS - 1));
size_t count = 0; // size_t is typically used to type indexes
while (mask > 0) {
if ((dec & mask) == 0) {
buf[count] = '0'; // operate on the buffer provided by the caller.
} else {
buf[count] = '1'; // operate on the buffer provided by the caller.
}
count++;
mask >>= 1; // same as: mask = mask >> 1;
}
buf[INT_BITS] = '\0'; // '0'-terminate the char-array to make it a C-string.
return buf;
}
Alternatively the function can be used like this:
int main(void)
{
...
showBits(i, buf);
printf("%d = 0b%s\n", i, buf);
}
The result printed should look like this in both cases:
42 = 0b00000000000000000000000000101010
A bit modified code - the caller should provide buff to accommodate the string
char *showBits(unsigned int dec, char *buf) {
unsigned int mask = 1u << 31;
int count = 0;
while (mask>0) {
if ((dec & mask) == 0) {
buf[count] = '0';
}
else {
buf[count] = '1';
}
count++;
mask = mask >> 1;
}
buf[count] = '\0';
return buf;
}

C - Write access violation

I have an error at the last line, in nullString, a function setting all the string to '\0' with a simple for()
void function ( unsigned char inputArray[], size_t inputSize )
{
size_t cellSize;
if (inputSize <= 256)
cellSize = 1;
else
cellSize = ceil(inputSize / 2 / 256) + 1;
// Sub Box
unsigned char subBox[255];
for (size_t line = 0; line < 255; line++)
subBox[line] = 0;
generate_SubBox(subBox, key);
// Sub Box
// Sub Box reverse
unsigned char subBox_Inverse[255];
for (size_t line = 0; line < 255; line++)
subBox_Inverse[line] = 0;
generate_SubBox_Inverse(subBox_Inverse, subBox, key);
// Sub Box reverse
unsigned char* inputArray2 = NULL;
inputArray2 = malloc(sizeof(unsigned char)* inputSize / 2);
verifyMalloc(inputArray2);
nullString(inputArray2, inputSize / 2);
unsigned char string_temp[3] = { 0 };
size_t w = 0;
for (size_t i = 0; i < inputSize / 2; i++)
{
string_temp[0] = inputArray[w];
string_temp[1] = inputArray[w + 1];
inputArray2[i] = strtoll(string_temp, NULL, 16);
w += 2;
}
}
I tried neutralizing line per line all instructions coming before nullString() by commenting them but it doesn't change anything.
If I neutralize nullString, the error comes after, at
inputArray2[i] = strtoll(...)
Hope you've got the answer :)
Thanks in advance !
EDIT:
Here is nullString:
void nullString(unsigned char input[], size_t length)
{
for (size_t x = 0; x < length; x++)
input[x] = '\0';
}
I commented all the instructions before nullString, the error is still there.
I also verified variables and they all look like good
EDIT 2:
verifyMalloc:
void verifyMalloc(int* pointer)
{
if (pointer == NULL)
{
perror("Erreur");
Sleep(15000);
exit(0);
}
}
Everything we're seeing is seriously hinting at you forgetting to #include <stdlib.h> (and ignoring the warnings resulting from that).
This is what might happens when you use malloc() without including stdlib.h in the same file:
the compiler consider the malloc() function to be declared implicitly, which means it is assuming that it's return types is int (instead of *void).
This might work when sizeof (int) is the same as sizeof (*void). But when int is 32-bits while pointers are 64-bits then the address returned by malloc() might lose half of it's bits and point to an invalid address.
Try using
void bzero(void *s, size_t n); or
void *memset(void *s, int c, size_t n);
instead of your nullString() and for()something[x]=0 loops.
Then, this does not make all of the array zeroed:
unsigned char string_temp[3] = { 0 };
This makes
string[0] = 0;
string[1] = god_knows;
string[2] = god_knows_not;
so either - unsigned char string_temp[3] = {0,0,0};
or bzero(string_temp,3);
Consequently, when you do this:
string_temp[0] = inputArray[w];
string_temp[1] = inputArray[w + 1];
inputArray2[i] = strtoll(string_temp, NULL, 16);
strtoll() will be guessing when to stop. No guarantee this would be at string_temp[2].
Then, this should be enough:
unsigned char* inputArray2 = malloc(sizeof(unsigned char) * inputSize / 2);
inputArray2 will be NULL if malloc failed, or a valid pointer if it succeeded.
You may want to check your inputSize / this_and_that arithmetics. Does it really deliver what you expect? You might be surprised by division result of integer operands.
This also looks suspicious:
inputArray2[i] = strtoll(string_temp, NULL, 16);
strtoll returns longlong integer but your inputArray2 is of unsigned char type. So you are trying to store 8 bytes (sizeof longlong = 8) and you reserved place only for one (sizeof char = 1)
Redeclare your inputArray2 as long long
long long *inputArray2 = malloc(sizeof(long long) * inputSize /2 );
And try this with memset():
size_t size = sizeof(long long) * inputSize/2;
//Do you really need long long? You are storing max three digits. uint_8 will be enough
long long* inputArray2 = malloc(size);
memset(inputArray2, 0, size);

Double from unsigned int[2]?

I have a 64-bit number written as two 32-bit unsinged ints: unsigned int[2]. unsigned int[0] is MSB, and unsigned int[1] is LSB. How would I convert it to double?
double d_from_u2(unsigned int*);
memcpy it from your source array to a double object in proper order. E.g. if you want to swap the unsigned parts
unsigned src[2] = { ... };
double dst;
assert(sizeof dst == sizeof src);
memcpy(&dst, &src[1], sizeof(unsigned));
memcpy((unsigned char *) &dst + sizeof(unsigned), &src[0], sizeof(unsigned));
Of course, you can always just reinterpret both source and destination objects as arrays of unsigned char and copy them byte-by-byte in any order you wish
unsigned src[2] = { ... };
double dst;
unsigned char *src_bytes = (unsigned char *) src;
unsigned char *dst_bytes = (unsigned char *) &dst;
assert(sizeof dst == 8 && sizeof src == 8);
dst_bytes[0] = src_bytes[7];
dst_bytes[1] = src_bytes[6];
...
dst_bytes[7] = src_bytes[0];
(The second example is not intended to be equivalent to the first one.)
There are several ways to copy the bits of your two integers into an object of type double.
At the lowest level, you can convert your input pointer to a [unsigned] char *, create a [unsigned] char * to the first byte of the return value, and copy between those by whatever means you choose. This provides you every opportunity to adjust byte order as may be needed -- for example, although your array is ordered most-significant word first, the order of the bytes within those words might not be what you need.
In the event that you need the bytes to be transferred into your double most-significant byte first, and that you do not want to depend on the machine byte order, you might do this:
double d_from_u2(unsigned int *in) {
double result;
unsigned char *result_bytes = (unsigned char *) &result;
for (int i = 0; i < 4; i++) {
result_bytes[i] = in[0] >> (24 - 8 * i);
result_bytes[i + 4] = in[1] >> (24 - 8 * i);
}
return result;
}
Using arithmetic (shifts, in this case) allows you to operate on the numeric values of the input independently of details of numeric representation.
Here is a solution that works without memcpybut using union:
#include "stdio.h"
#include "stdint.h"
double d_from_u2(unsigned int* v) {
union {
int32_t x[2];
int64_t y;
} u = { .x = { v[1], v[0] }};
printf("%llu\n", u.y); // 1311768467463794450
return (double)u.y;
}
int main(void) {
int32_t x[2];
x[0] = 0x12345678;
x[1] = 0x9abcef12;
printf("%f\n", d_from_u2(x)); // 1311768467463794432.000000
return 0;
}
See demo. In initializes the array int32_t[2] in the union and uses the int64_t to convert it to a double. The order of the initialization depends on which machine (little or big endian) it runs or where the values comes from (1 first).

copying between variables in C

I want to copy an unsigned int value to a char[2] variable. I presume the copying is straight forward since both of them have the same size (16 bits). Here's my code:
#include <stdlib.h>
#include <stdio.h>
int main()
{
unsigned short a = 63488; //16 bit value which is 1111100000000000;
unsigned char* b = malloc(2);
*b = a;
printf("%d\n",b[0]); // I expect the lower part here which is 0
printf("%d\n",b[1]); // I expect the higher part here which is 11111000
return 0;
}
But my result shows zero values. Do I have to copy each part separately? Isn't there any other easier method to do that?
Thank you
If you just want to interpret the short as a char array, you don't even need to copy. Just cast:
#include <stdio.h>
int main()
{
size_t i;
unsigned short a = 63488;
unsigned char* b = (unsigned char*)&a; // Cast the address of a to
// a pointer-to-unsgigned-char
printf("Input value: %d (0x%X)\n", a, a);
printf("Each byte:\n");
for (i = 0; i < sizeof(a); i++)
printf("b[%d] = %d (0x%X)\n", i, b[i], b[i]);
return 0;
}
Output:
$ gcc -Wall -Werror so1.c && ./a.out
Input value: 63488 (0xF800)
Each byte:
b[0] = 0 (0x0)
b[1] = 248 (0xF8)
Note that I ran this on my x86 PC, which is a little endian machine, which is why the first byte is the low byte of the input.
Also note that my code also never makes assumptions about the size of short.
Try like this
memcpy(b, &a, sizeof(a));
Or
b[0] = a & 0xFF;
b[1] = (a >> 8) & 0xFF;
Note that b is of type unsigned char so assigning to *b should be a value of the same type or the value will be truncated.

Resources