0

I want to set up a variable with any value whatsoever for a program. The best thing I can do is using var, but the var keyword doesn't exist in C.

I tried this code:

#include <stdio.h>

int main() {
    var a = 2;
    puts(a);
}

Then got these errors:

var.c:4:5: error: use of undeclared identifier 'var'
    var a = 2;
    ^
var.c:5:10: error: use of undeclared identifier 'a'
    puts(a);
         ^

If not var, then what's an equivalent for it in C?

  • 3
    No, there is no equivalent. But there might be specific solutions to specific problems. – Eugene Sh. May 14 '21 at 19:01
  • 3
    C is strictly typed, so you'll need to explicitly define variables with a type. For whatever it's worth, in C++ the `auto` keyword can perform type inference, but C++ is not the same as C. – h0r53 May 14 '21 at 19:04
  • @Carcigenicate Use something like `var` so I can use it more on C in the future. – Stack Exchange May 14 '21 at 19:05
  • 1
    When you say "a variable with any value whatsoever for a program" you probably _shouldn't_ be using variables in C that way. You could use a C-String to store your raw data and create parsing logic on your own, but otherwise what you're suggesting is known as dynamic typing, which isn't allowed in C. – h0r53 May 14 '21 at 19:06
  • Since C++ 17, there is [`std::any`](https://en.cppreference.com/w/cpp/utility/any), which serves exactly this purpose. Maybe is it possible to write your own if you can't afford to switch language... – ljleb May 14 '21 at 19:07
  • 3
    When you're learning a new language you're learning a new language. Don't look for equivalents for everything. Quite often you need to rethink everything when switching language. – klutt May 14 '21 at 19:20
  • What is the actual problem you're trying to solve with this? – klutt May 14 '21 at 19:22
  • `puts(2);` does not make much sense. || Anyway, one prominent mention is a rather unused (or used only in a special edge case) GNU compiler extension [__auto_type](https://gcc.gnu.org/onlinedocs/gcc-11.1.0/gcc/Typeof.html#Typeof). – KamilCuk May 14 '21 at 19:25
  • @Louis-JacobLebel : While there are ways of implementing variant types (easier in C++ than C as you suggest), you'd also need functions capable of accepting such types - `putc()` will remain as strongly typed as ever and requires a `char*` argument. So the your suggestion does not do "exactly that" in C or C++. – Clifford May 14 '21 at 19:29
  • @Clifford in C++ `std::any` has to be cast using [`std::any_cast`](https://en.cppreference.com/w/cpp/utility/any/any_cast) in order to be used in code working with specific types. I would expect this function / method to be part of a C implementation as well (again, in the case `std::any` can be implemented in C at all). – ljleb May 14 '21 at 19:30
  • @Louis-JacobLebel : "Use C++" is not really a useful answer to a C question. The question does not have a strong case for using a variant type as it is trivially solved by using a more appropriate output function. If he really needs a `var`, he'll have to make a stronger case and explain why it cannot be done some other way. In this case there are methods of outputting integer values to stdout that do not need a variant type. – Clifford May 14 '21 at 20:03
  • 1
    @Louis-JacobLebel Apologies; you are commenting on a comment I deleted. But _really_? If you were using C++ you'd use an `std::ostream` object (`cout`), where the appropriate `operator<<` overload would be invoked. You are really overcomplicating the issue. While yes you are answering the question directly; it is also the case that it is not idiomatic, and a `var` is seldom an appropriate solution. in C or C++. Agreed though - let's stop now! – Clifford May 14 '21 at 20:07
  • @Clifford Now that I think about it, you're very right. There is generally a better way to implement polymorphism (and it's even more true in this case with `puts`). Also, I cleaned up what I could of this thread. Don't hesitate to remove comments you believe are not relevant anymore! – ljleb May 14 '21 at 20:26

4 Answers4

4

Scripting languages which are written in C manage to implement this for their variables. However, it is quite complicated.

C needs to know the size of things, so that it can place them into memory correctly. A variable must always be of a known type and size.

In order to have a variable of unknown type, you need to create a struct something like this (off the top of my head, untested but see https://github.com/zlynx/type-union-test):

struct var {
    enum {
        INT,
        OBJ,
        DOUBLE,
    };
    union {
        long i;
        void* p;
        double d;
    };
};

And then functions to operate on everything. Implementing OBJ gets fun because you need more structs defining if it is an array or another var, etc.

Anyway. If you're looking to make programming in C easier then don't try this. Decide up front what your variable is.

Zan Lynx
  • 53,022
  • 10
  • 79
  • 131
0

If you can use pointers, you can use void *:

#include <stdio.h>

int main() {
 char *s = "abc";
 void *a = s;
 puts(a);

 return 0;
}
user2233706
  • 6,148
  • 5
  • 44
  • 86
  • Thanks. Never heard of `void *` so I'll look into that. – Stack Exchange May 14 '21 at 19:10
  • 2
    The OP seem to expect that the compiler can infer the type and use some kind of type-specific functionality. Such that if `a` is pointing to `int`, then `puts(a);` will print it as a number. Which is obviously not going to work. – Eugene Sh. May 14 '21 at 19:12
  • Yes all variables have a memory location, so technically you could use a pointer to store any type. However, doing so will likely further complicate the process of type resolution. You're going to end up needing to cast your type regardless, and to do so reliably you need some idea of what the type is _supposed_ to be. Thus, I strongly discourage this practice as a way to create "one size fits all types" in C. – h0r53 May 14 '21 at 19:12
  • Also worth noting, `void *` is technically a function pointer. On a given system, all pointers have the same size in C. So it doesn't matter if the address being pointed to contains a function, an `int`, a `char`, etc. However, to reliably use your data you're going to need to know what type is being pointed at. So this doesn't really solve anything. If you know the correct type, just use it and save yourself the headache of adding type ambiguity. – h0r53 May 14 '21 at 19:17
  • @StackOverflow : look it it by all means, but I cannot see how, and this answer does not explain how it solves your problem. – Clifford May 14 '21 at 19:31
  • @h0r53: Well actually, [`void *` is *not* guaranteed to be able to store a function pointer](https://stackoverflow.com/questions/36645660/why-cant-i-cast-a-function-pointer-to-void?rq=1), and [pointers do not all have to have the same size](https://stackoverflow.com/questions/1241205/are-all-data-pointers-the-same-size-in-one-platform-for-all-data-types). (Though those are true on many common systems.) In general, all one knows is that a pointer to any type (other than function) can be converted to `void *` and back, and still work. – Nate Eldredge May 15 '21 at 06:33
0

C is statically typed. That means all variable have a specific type, and all function arguments and return values have a specific type. Moreover it means that when assigning a variable, passing a parameter or returning a value, the value must either match the specified type or be compatible/convertible to that type within the rules of the language.

This may seem inconvenient, but C is a systems-level language capable interaction directly with memory and I/O efficiently and in a systems level language strong typing is essential. There is a remarkable amount of code related to supporting weakly types languages; in C it is simply a memory location of the appropriate and fixed size.

In your example you have an integer value 2 in a variable, but you want to print a string using puts() that requires a char* argument referring to a NUL terminated string. The idiomatic C way of solving this problem is yo use a function that will generate a string representation of the integer value. Because C will not "magically" perform that conversion for you, it has a library that handles the most common conversion and presentation requirements. In this case:

#include <stdio.h>

int main() 
{
    int a = 2;
    printf( "%d\n", a ) ;
}

In this case the printf() uses the %d format specifier to present the integer 2 as a string "2" followed by a newline. The string "2" being a character with code 0x32 or 50 decimal (assuming ASCII encoding).

If you still think you need a variant, (because clearly in the example it is not at all necessary), then ask a new question with a more concrete example of the problem you are trying to solve - you will no doubt get an answer showing how to solve the problem in C - not all solutions are as easy as this.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

As others mentioned already, at the end of the day you need to know the type of the variables in order to do something with them.

Besides void * pointers, you may also treat everything as c-strings (nul-terminated buffers of chars), then use any of the C99 strto* family of functions (float*, signed*, unsigned*) to convert them to their intended type on-demand.

For example, the following declares a as a c-string and outputs its float, long int and unsigned long representations:

char *a = "-2.3";
printf( "float: %f\n", strtof(a, NULL) );
printf( "long: %ld\n", strtol(a, NULL, 10) );
printf( "unsigned long: %lu\n", strtoul(a, NULL, 10) );

Output:

float: -2.300000
long: -2
unsigned long: 4294967294

You can do more fancy stuff with those functions (and even more with void * pointers) but neither of them answers exactly your question, because what you asked is not directly supported by C.

Both suggestions fight against the nature of the language. If you are to use C, just learn and use the supporting types (or define your own, which is also well supported).

Harry K.
  • 560
  • 3
  • 7