Weird behaving ellipsis function (va_list) - c

The following max function is supposed to return 5 but it returns 4294967294 instead. I suspect the weird behavior arise from casting variables but couldn't figure it out. Can someone detect the fault?
System: Windows 7 (64 bits), mingw64
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <stdarg.h>
#include <inttypes.h>
int64_t max(int64_t n, ...) {
va_list v;
int64_t i, t, max = INT64_MIN;
va_start(v, n);
for (i = 0; i < n; i++) {
t = va_arg(v, int64_t);
if (max < t) {
max = t;
}
}
va_end(v);
return (max);
}
int main(int argc, char **argv) {
printf("max(3, 1, 5, -2) : %3I64d\n", max(3, 1, 5, -2));
return (0);
}

The compiler doesn't know that 1,5 and -2 are supposed to be type int64_t. So it will treat them as normal ints and will only use that much space on the stack for them.
You then read them as int64_t which is certainly larger than int and so your input and your var_args are out of alignment.
One way to fix, cast to int64_t at the call site.
printf("max(3, 1, 5, -2) : %"PRId64"\n", max(3, (int64_t)1, (int64_t)5, (int64_t)-2));
You could also obviously explicitly pass int64_t typed variables.

Related

How to calculate ELF format .data section size manually

I'd like to calculate the size of .data section in my program (compiled with gcc with no optimization) WITHOUT using readelf or any other tool, just by looking at the program. Is this possible? Here is the program:
ex1.h
#include <stdint.h>
#include <inttypes.h>
#define FORMAT_STRING "%s%" PRId64
#define MESSAGE "The Oddonaci Number is: "
int64_t FastOddonacci(int32_t n);
int64_t LinearOddonacciHelper(int32_t n, int64_t current, int64_t first, int64_t second, int64_t third);
ex1.c
#include "ex1.h"
#include <stdio.h>
int32_t n = 40;
int32_t a = 3;
int main(int argc, char* argv[]) {
printf(FORMAT_STRING, MESSAGE, FastOddonacci(n * a));
return 0;
}
int64_t FastOddonacci(int32_t n) {
if (n >= 1 && n <= 3) {
return 1;
}
return LinearOddonacciHelper(n, 3, 1, 1, 1);
}
int64_t LinearOddonacciHelper(int32_t n, int64_t current, int64_t first, int64_t second, int64_t third) {
if (n == current) {
return third;
}
current += 1;
return LinearOddonacciHelper(n, current, second, third, first+second+third);
}
From my understanding, .data section contains all initialized variables so here we should have two: n and a. The two in #define should go to .rodata instead. So we have 8 bytes in total.
However, readelf told me that the size is 0x18 = 24 bytes, why?
A second test: I changed both n and a to int64_t (and changed the signature of those functions) and readelf shew 32 bytes, which does make sense as the difference is exactly 8 bytes. Where is the missing 16 bytes? It doesn't look like alignment though.

Adding Two numbers with using only one variable in C

I was trying to create a program that inputs two number and outputs their sum. For this I must have to use two variables. I was just curious whether this can be done by using only one variable.
Note : user has to input two numbers.
#include<stdio.h>
int main()
{
int a, b;
scanf("%d%d",&a,&b);
printf("%d",(a+b));
return 0;
}
#include <stdio.h>
int main ( void )
{
int a[3];
scanf("%d", &a[0]); /* first number */
sscanf("%d", &a[1] ); /* second number */
a[2] = a[0] + a[1];
printf("sum is %d\n", a[0] + a[1] );
printf("sum stored in a[%d] is %d\n", 2, a[2] );
return 0;
}
Technically one variable, a pointer:
#include<stdio.h>
int main() {
int *nums = malloc(2 * sizeof(int));
scanf("%d%d",nums, (nums + sizeof(int)));
printf("%d",(*nums + *(nums + sizeof(int))));
return 0;
}
But no there isn't really an elegant way to use one variable for two inputs.
Note that I've considered the question like a challenge or a puzzle. Do not consider this answer good C practice. Obviously the cleanest way to make a sum of 2 values from input is to use 2 variables. I still find the challenge interesting though.
#include <stdio.h>
#include <math.h>
int main()
{
int a;
printf("%g", fmin((scanf("%d", &a), a), 1.0/0.0 + rand()) + fmin((scanf("%d", &a), a), 1.0/0.0 + rand()));
return 0;
}
Works with negative values.
I'm using the comma operator which executes both expressions but only return the second one. So (scanf("%d", &a), a) is like calling scanf("%d", &a) and returns a. I pass this result through a function (any function) as I want to prevent updating the value (to sum it with the new a). I have no idea if your compiler will call the left or right part of the big expression first but it doesn't matter as both are doing the same thing. Whichever executes first will be the first value from input.
fmin(x, 1.0/0.0 + rand()) makes sure nothing is inlined by the compiler. 1.0/0.0 is Infinity and would never be returned in fmin() in our case. Compiler would inline this to x normally but adding + rand() to Infinity (which is still Infinity) seems to prevent it.
You can even do it by declaring "0" variable by using argc:
#include <stdio.h>
#include <math.h>
int main(int a)
{
printf("%g", fmin((scanf("%d", &a), a), 1.0/0.0 + rand()) + fmin((scanf("%d", &a), a), 1.0/0.0 + rand()));
return 0;
}
I've used this to test: https://www.onlinegdb.com/online_c_compiler
Adding Two numbers with using only one variable in C
Create a helper function with the 1 variable.
#include <stdio.h>
int scan_int(void) {
int a;
if (scanf("%d", &a) == 1) {
return a;
}
return 0;
}
int main(void) {
printf("Sum %d\n", scan_int() + scan_int());
return 0;
}
Note that scan_int() + scan_int(), code could call either the left or the right scan_int() first (or in parallel). Fortunately + is commutative, so it makes no difference here.
The "trick" here is that there exist in sequence or in parallel, a 1st_call_scan_int::a and 2nd_call_scan_int::a. Still only one variable in code.
OK, there's been quite a few interesting answers, but weirdly nobody has thought of the obvious way to store 2 ints in a single variable - structs:
#include<stdio.h>
typedef _in struct {
a int
b int
} inp;
int main(void)
{
inp input;
scanf("%d%d",&input.a,&input.b);
printf("%d",input.a+input.b);
return 0;
}
int main(void) {
int *num = malloc(sizeof(int)*2);
scanf("%d %d", num, num+1);
printf("%d\n", num[0] + (num[1]));
}
int *num = malloc(sizeof(int)*2); //two int space
scanf("%d %d", num, num+1); // num (pos 0), num+1 (pos1)
printf("%d\n", num[0] + (num[1])); //the sum of the positions
Only one variable - no tricks. As many numbers can be added as you want :)
#include <stdio.h>
int ScanAndAdd(void)
{
int a;
if(scanf("%d", &a) != 1) return 0;
return a + ScanAndAdd();
}
int main()
{
printf("%d\n", ScanAndAdd());
return 0; /**/
}
One way to do it is.
#include <stdio.h>
int x;
int enter(){
scanf("%d",&x);
return x;
}
int main()
{
x=enter()+enter();
print("sum of two number is %d",x);
return 0;
}
Another way to do it..
#include <stdio.h>
int main()
{
int x;
scanf("%d",&x);
printf("next no. ");
x= x*(scanf("%d",&x))+x;
printf("%d",x);
return 0;
}
Although the second one is not consistent, in some compiler it works perfectly and in some, it doesn't
#include <stdio.h>
int main()
{
long long int buffer=0;
scanf("%d",(int*)&buffer);
scanf("%d",(int *)&buffer+1);
printf("\nsum is %d\n",*((int*)&buffer)+*((int*)&buffer+1));
return 0;
}
Try this on for size. It uses fixed width C99 types to guarantee that memory alignment works as intended. It even does the 32-bit arithmetic in a uint64_t type to prevent overflow issues. This will work with any of the other fixed-width integer types, signed or unsigned, with trivial modification.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main (void)
{
uint64_t a;
scanf ("%" SCNu32 "%" SCNu32, (uint32_t*)&a, (uint32_t*)&a + 1);
printf ("%" PRIu64 "\n", (uint64_t)((uint32_t*)&a)[0] +
((uint32_t*)&a)[1]);
}
The above code was modified from my original answer, seen below. I removed the void* cast in (uint32_t*)(void*)&a because it was unnecessary. I also cleaned up the scanf arguments to increase readability, and added a new line to the end of the printf format argument.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main (void)
{
uint64_t a;
scanf ("%" SCNu32 "%" SCNu32,
&((uint32_t*)(void*)&a)[0], &((uint32_t*)(void*)&a)[1]);
printf ("%" PRIu64, (uint64_t)((uint32_t*)(void*)&a)[0] +
((uint32_t*)(void*)&a)[1]);
}

Incorrect single precision floating point representation on ubuntu 64 bit

I have the following data.
float u[4] = {0x3f951d32, 0x3f207887, 0x3d99c3a0, 0x3eb405d2};
ScaleFunction(u);
void ScaleFunction(float *u_ptr)
{
for(int i = 0; i < 4; i++)
{
printf("u[%d] = %f\n", u_ptr[i]);
}
// And a lot more
}
The application containing the snippet above is executed on a 64 bit machine running ubuntu 16.10.
Much to my chagrin, the floating point numbers are incorrectly interpreted as: 1066736960.000000, 1059092608.000000, 1033487232.000000 and 1051985344.000000.
The numbers when printed in hexadecimal confirm that the caller passes the correct values to callee.
What am I doing wrong here?
I even tried the following with no joy.
uint32_t u[4] = {0x3f951d32, 0x3f207887, 0x3d99c3a0, 0x3eb405d2};
ScaleFunction(u);
void ScaleFunction(uint32_t *u_ptr)
{
float ut[4];
for(int i = 0; i < 4; i++)
{
ut[i] = (float) u_ptr[i];
printf("ut[%d] = %f\n", ut[i]);
}
// And a lot more
}
I expect to interpret the hexadecimals in the callee as:
1.1649, 0.6268, 0.075, 0.5516
The problem is, that you initialize your array with large integer values, not the hex representation of the floats. With your hex constants starting with values around 0x3f it's pretty clear that these are floating point data with values around 1.0.
As far as I know there is no direct way to initialize a float array with hex constants (if there is one, community, please tell me!).
So you have to define your data-array as int and convert it to float as you use it. IMPORTANT: Directly casting the pointer from int to float will break the aliasing rule of C and may result in code that looks correct but misbehaves.
Converting between the two data-types via memcpy is safe though and the compiler is usually smart enough to spot this and optimize it out.
So this solution here does what you want:
#include <stdint.h>
#include <stdio.h>
#include <string.h>
uint32_t u[4] = {0x3f951d32, 0x3f207887, 0x3d99c3a0, 0x3eb405d2};
void ScaleFunction(uint32_t *u_ptr)
{
for(int i = 0; i < 4; i++)
{
float temp;
memcpy (&temp, &u[i], sizeof (float));
printf("u[%d] = %f\n", i, temp);
}
// And a lot more
}
void main (int argc, char **args)
{
ScaleFunction (u);
}
You code cannot work as you think: you are assigning integers to your float. You are not assigning the HEX values as float.
Best thing you can do is to have a init array and copy it to your float array
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
uint32_t init[] = {0x3f951d32u, 0x3f207887u, 0x3d99c3a0u, 0x3eb405d2u};
void ScaleFunction(float *u_ptr, size_t size)
{
for(size_t i = 0; i < size; i++)
{
printf("u[%zu] = %f\n", i, u_ptr[i]);
}
// And a lot more
}
int main (void)
{
assert ( sizeof(float) == sizeof(uint32_t) );
float u[sizeof(init)/sizeof(init[0])];
memcpy(u, init, sizeof(init));
ScaleFunction(u, sizeof(init)/sizeof(init[0]));
}

Getting the size of varargs in C?

I am trying to convert some Java code into C. The Java code goes like this:
public static int minimum( int... minimum ) {
assert( minimum.length > 0 );
if ( minimum.length > 0 )
.... // some code that i am able to translate to C without any hassle
}
Now I understand how to have varargs in C by using the stdarg.h header and using the macros provided. However I am stuck doing the minimum.length part.
I have tried strlen but the terminal is giving me an incompatible integer to pointer conversion warning. Is there any way in C where I can replicate the same thing that Java does?
Not directly, as pointed out by #MichaelBurr, you need to pass the number of elements or use a sentinel.
An indirect way to do this is using compound literals:
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#define minimum(...) fnminimum(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__)
static int fnminimum(int n, ...)
{
int num, min = INT_MAX;
va_list ap;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
if (num < min) {
min = num;
}
}
va_end(ap);
return min;
}
int main(void)
{
int a = 1;
printf("%d\n", minimum(2, 30, 7, a++, 4));
return 0;
}
Another (ugly) method using NARGS macros (limited to N args):
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define minimum(...) fnminimum(NARGS(__VA_ARGS__), __VA_ARGS__)
static int fnminimum(int n, ...)
{
int num, min = INT_MAX;
va_list ap;
va_start(ap, n);
while (n--) {
num = va_arg(ap, int);
if (num < min) {
min = num;
}
}
va_end(ap);
return min;
}
int main(void)
{
printf("%d\n", minimum(2, 30, 7, 1, 4));
return 0;
}
Output:
1
There is no built-in way to get the number of vararg arguments passed in C.
You need to do one of the following:
pass in a count explicitly,
pass in a count implicitly (as printf() does via the number of conversion specifiers)
or use a sentinel value (such as NULL or 0) to indicate the end of the vararg list
I have seen schemes that use macros and the __VA_ARGS__ identifier to automatically place a sentinel at the end of the varargs list when calling a function.

How to change datatypes in c

I have a function, which adds the given arguments and prints the result.
With integer numbers, there were no problems at all. Used atoi to change string argument -> int.
e.g. : ./main 3 4 5 will print 12.
But if I have ./main 4.5 6 5.5 ?how do I do something like this in C? How can the function "see", that it has to change the argument types now to float?
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[] )
{
int i , sum = 0;
for(i=1; i < (argc); ++i)
sum += atol(argv[i]);
printf("%d\n", sum);
return 0;
}
In c, there is no function overloading as in c++, thus you should use atof, like this:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[] )
{
int i;
double sum = 0;
for(i = 1; i < (argc); ++i)
sum += atof(argv[i]);
printf("%f\n", sum);
return 0;
}
to treat numbers as reals, not integers.
Output:
gsamaras#gsamaras-A15:~$ ./a.out 4.5 6 5.5
16.000000
since now 6 is treated like 6.0.
You might want to read this as well: How to convert string to float?
I have tested the code below. It will print the float number upto 2 decimal places.
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char* argv[] )
{
int i;
double sum = 0;
for(i=1; i<argc; i++)
sum += atof(argv[i]);
printf("%.2f\n", sum);
return 0;
}
You should use double to store floating point numbers, atof to parse strings and the %f printf specifier.
Although I get an implicit declaration warning for strtod (because the linux manual doesn't tell me the correct includes to use), this code below does work:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
int i;
double sum=0;
for(i=1; i < argc; ++i)
sum += strtod(argv[i],NULL);
printf("%f\n", sum);
return 0;
}
The manual also states the following as an issue with using atoi():
The atoi() function converts the initial portion of the string pointed to by nptr to int.
The behavior is the same as
strtol(nptr, (char **) NULL, 10);
except that atoi() does not detect errors.

Resources