I'm mainly an electronics hardware guy, but I've learned the basics of D from a friend, so I decided I'd pick up a more standard language like C. So, any advice would be great.
Basically, I'm using the integer 'phew' as a counter, to reverse all numbers. Super basic, but I'm having trouble finding the way to do this in C. My code:
#include <stdio.h>
int main()
{
int input;
int phew;
printf("Binary Number: ");
scanf("%d", &input);
while(phew < sizeof(input))
{
if(input[phew] == 0)
printf("1");
else
printf("0");
phew++;
}
return 0;
}
And the compiler error was:
helloworld.c: In function ‘main’:
helloworld.c:11:11: error: subscripted value is neither array nor pointer nor vector
if(input[phew] == 0)
^
First of all, in the below statement,
while(phew < sizeof(input))
invokes undefined behavior as phew is an automatic local variable and not initialized. You need to initialize phew like int phew = 0;
In this scenario, sizeof(input) is valid, but does not make any sense.
That said, you can only use the [] operator on an array type. In your case, input is an int, so you are not allowed to write input[n].
to elaboate, quoting the C11 standard, chapter §6.5.2.1
Syntax
postfix-expression [ expression ]
and the description
One of the expressions shall have type pointer to complete object type, the other
expression shall have integer type, and the result has type type.
So, clearly, in your case input is not a "pointer-to-type", hence the error.
To solve the issues,
You can change the type of input as char input[32] = {0};
change the scan statement as `scanf("%29s", input);
add while(phew < strlen(input))
to make sense. You'll be needing string.h header file for that. Check details about strlen() here.
You have to change it like
while(phew < strlen(input) )
{
if(input[phew] == '0') //ASCII 48, decimal
printf("1");
else
printf("0");
phew++;
}
You cannot use [] to get bits of an integer in C; that operator only works on pointer values and an int is not a pointer. You may be familiar with Verilog, where bit vectors and integers are the same thing; but C doesn't have a syntax for accessing bits of an object and [] is only for accessing members of an array.
One correct way to do this is using a bit mask. For example:
for (size_t i = 0; i < (sizeof input)*CHAR_BIT; i++) {
unsigned mask = 1 << i;
if (input & mask) {
putchar('1');
} else {
putchar('0');
}
}
putchar('\n');
What this code does on each iteration of the loop is create an unsigned integer mask by shifting the number 1 into the ith place of the integer. Then mask is bitwise-ANDed with input to give a value that is 0 if that bit is 0 in input (and otherwise some nonzero value equivalent to the place value of the bit). Don't forget to print out a newline at the end or the output may not be visible.
I'm using unsigned arithmetic here because << can have implementation-defined or undefined behavior on signed numbers in C. input can be a regular (signed) int because it will be promoted to unsigned by the & operator.
Also notice that I had to multiply sizeof input by CHAR_BIT (which is defined in <limits.h>) to get the number of bits; sizeof always measures sizes in bytes.
Also see this C FAQ (20.7) about bit manipulations.
Related
I'm making a function that takes a value using scanf_s and converts that into a binary value. The function works perfectly... until I put in a really high value.
I'm also doing this on VS 2019 in x64 in C
And in case it matters, I'm using
main(int argc, char* argv[])
for the main function.
Since I'm not sure what on earth is happening, here's the whole code I guess.
BinaryGet()
{
// Declaring lots of stuff
int x, y, z, d, b, c;
int counter = 0;
int doubler = 1;
int getb;
int binarray[2000] = { 0 };
// I only have to change things to 1 now, am't I smart?
int binappend[2000] = { 0 };
// Get number
printf("Gimme a number\n");
scanf_s("%d", &getb);
// Because why not
printf("\n");
// Get the amount of binary places to be used (how many times getb divides by 2)
x = getb;
while (x > 1)
{
d = x;
counter += 1;
// Tried x /= 2, gave me infinity loop ;(
x = d / 2;
}
// Fill the array with binary values (i.e. 1, 2, 4, 8, 16, 32, etc)
for (b = 1; b <= counter; b++)
{
binarray[b] = doubler * 2;
doubler *= 2;
}
// Compare the value of getb to binary values, subtract and repeat until getb = 0)
c = getb;
for (y = counter; c >= 1; y--)
{
// Printing c at each subtraction
printf("\n%d\n", c);
// If the value of c (a temp variable) compares right to the binary value, subtract that binary value
// and put a 1 in that spot in binappend, the 1 and 0 list
if (c >= binarray[y])
{
c -= binarray[y];
binappend[y] += 1;
}
// Prevents buffer under? runs
if (y <= 0)
{
break;
}
}
// Print the result
for (z = 0; z <= counter; z++)
{
printf("%d", binappend[z]);
}
}
The problem is that when I put in the value 999999999999999999 (18 digits) it just prints 0 once and ends the function. The value of the digits doesn't matter though, 18 ones will have the same result.
However, when I put in 17 digits, it gives me this:
99999999999999999
// This is the input value after each subtraction
1569325055
495583231
495583231
227147775
92930047
25821183
25821183
9043967
655359
655359
655359
655359
131071
131071
131071
65535
32767
16383
8191
4095
2047
1023
511
255
127
63
31
15
7
3
1
// This is the binary
1111111111111111100100011011101
The binary value it gives me is 31 digits. I thought that it was weird that at 32, a convenient number, it gimps out, so I put in the value of the 32nd binary place minus 1 (2,147,483,647) and it worked. But adding 1 to that gives me 0.
Changing the type of array (unsigned int and long) didn't change this. Neither did changing the value in the brackets of the arrays. I tried searching to see if it's a limit of scanf_s, but found nothing.
I know for sure (I think) it's not the arrays, but probably something dumb I'm doing with the function. Can anyone help please? I'll give you a long-distance high five.
The problem is indeed related to the power-of-two size of the number you've noticed, but it's in this call:
scanf_s("%d", &getb);
The %d argument means it is reading into a signed integer, which on your platform is probably 32 bits, and since it's signed it means it can go up to 2³¹-1 in the positive direction.
The conversion specifiers used by scanf() and related functions can accept larger sizes of data types though. For example %ld will accept a long int, and %lld will accept a long long int. Check the data type sizes for your platform, because a long int and an int might actually be the same size (32 bits) eg. on Windows.
So if you use %lld instead, you should be able to read larger numbers, up to the range of a long long int, but make sure you change the target (getb) to match! Also if you're not interested in negative numbers, let the type system help you out and use an unsigned type: %llu for an unsigned long long.
Some details:
If scanf or its friends fail, the value in getb is indeterminate ie. uninitialised, and reading from it is undefined behaviour (UB). UB is an extremely common source of bugs in C, and you want to avoid it. Make sure your code only reads from getb if scanf tells you it worked.
In fact, in general it is not possible to avoid UB with scanf unless you're in complete control of the input (eg. you wrote it out previously with some other, bug free, software). While you can check the return value of scanf and related functions (it will return the number of fields it converts), its behaviour is undefined if, say, a field is too large to fit into the data type you have for it.
There's a lot more detail on scanf etc. here.
To avoid problems with not knowing what size an int is, or if a long int is different on this platform or that, there is also the header stdint.h which defines integer types of a specific width eg. int64_t. These also have macros for use with scanf() like SCNd64. These are available from C99 onwards, but note that Windows' support of C99 in its compilers is incomplete and may not include this.
Don't be so hard on yourself, you're not dumb, C is a hard language to master and doesn't follow modern idioms that have developed since it was first designed.
I would like try to understand how is working the compilator when we compare an enumerate with invalid value, and what the program is doing during execution.
I found strange source code during my work, and did not understand the behaviour of the program, which was not giving me the expected result.
I wrote the following little program to summarize my problem.
I create an enum E_Number and I instanciate a variable a, with the value -1.
Then I perform comparison on a to check if it belongs to the range of the enum.
(I know, this is really strange, but this is exactly what i found in source code !)
I expected the result tells me Not in range because of the fail of the first condition (a >= FIRST_ENUM).
But it was the fail of the second condition (a < NB_MAX_NUMBER) which gave me the right result (see the printf())...
If I cast a in (int) in the if conditions, I get excepted results.
So what is happening during the execution ? Is the program considering -1 as an other possible enum value which will be positionned after NB_MAX_NUMBER ? What is the rule for > and < operator on enum ?
#include <stdio.h>
#define FIRST_ENUM 0
typedef enum{
NUM_1 = FIRST_ENUM,
NUM_2,
NUM_3,
NB_MAX_NUMBER
}E_Number;
int main()
{
E_Number a = -1;
if ((a >= FIRST_ENUM) && (a < NB_MAX_NUMBER))
{
printf("In Range\n");
}
else
{
printf("Not in Range\n");
}
printf("1st condition = %s\n", (a >= FIRST_ENUM)?"TRUE":"FALSE");
printf("2nd condition = %s\n", (a < NB_MAX_NUMBER)?"TRUE":"FALSE");
return 0;
}
gcc program.c
.\a.exe
Not in Range
1st condition = TRUE
2nd condition = FALSE
I am working with MINGW compilator ( gcc (x86_64-win32-seh-rev1, Built by MinGW-W64 project) 4.9.2 )
In your case the compiler consider E_Number as unsigned int because all the legal values are unsigned, so -1 is considered to be ~0u which is >= FIRST_ENUM and < NB_MAX_NUMBER
I have the same behavior with gcc version 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1+deb9u1)
pi#raspberrypi:~ $ ./a.out
Not in Range
1st condition = TRUE
2nd condition = FALSE
But, if I change your definitions like that :
#include <stdio.h>
#define FIRST_ENUM -1
typedef enum{
NUM_1 = FIRST_ENUM,
NUM_2,
NUM_3,
NB_MAX_NUMBER
}E_Number;
int main()
{
E_Number a = -2;
if ((a >= FIRST_ENUM) && (a < NB_MAX_NUMBER))
{
printf("In Range\n");
}
else
{
printf("Not in Range\n");
}
printf("1st condition = %s\n", (a >= FIRST_ENUM)?"TRUE":"FALSE");
printf("2nd condition = %s\n", (a < NB_MAX_NUMBER)?"TRUE":"FALSE");
return 0;
}
the behavior change and the enum is considered to be an int and I have :
pi#raspberrypi:~ $ ./a.out
Not in Range
1st condition = FALSE
2nd condition = TRUE
Enumarator constants are of type int. The enumerator type is an unspecified integer type capable of representing all the enumerator constants.
6.7.2.2p4:
Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined,128) but shall be capable of representing the
values of all the members of the enumeration. The enumerated type is
incomplete until immediately after the } that terminates the list of
enumerator declarations, and complete thereafter.
Since you haven't enumerated any negative values, that type may well be an unsigned type. If it is, then (E_Number)some_integer will always be greater than or equal to zero (0==FIRST_ENUM).
If you expand the enum list to:
typedef enum{
NUM_NOPE=-1,
NUM_1 = FIRST_ENUM,
NUM_2,
NUM_3,
NB_MAX_NUMBER
}E_Number;
you'll force the compiler to use a signed type and the results will reverse.
Quote from ISO/IEC 9899:1999, 6.7.2.2p3
Each enumerated type shall be compatible with char, a signed integer
type, or an unsigned integer type. The choice of type is
implementation-defined, 108) but shall be capable of representing the
values of all the members of the enumeration.
So, when you declare an enumeration, you cannot be sure a priori about what kind of data will the implementation of C choose to store that variable. Optimisation reasons, the compiler may not choose an integer type on 4 bytes if you store enumeration constants between [-128, +127]. The implementation may choose char to store an enumerated variable, but you cannot be sure. Any integer data type can be chosen as time as it can store all possible values.
I was working on Exercise 2-1 of K&R, the goal is to calculate the range of different variable types, bellow is my function to calculate the maximum value a short int can contain:
short int max_short(void) {
short int i = 1, j = 0, k = 0;
while (i > k) {
k = i;
if (((short int)2 * i) > (short int)0)
i *= 2;
else {
j = i;
while (i + j <= (short int)0)
j /= 2;
i += j;
}
}
return i;
}
My problem is that the returned value by this function is: -32768 which is obviously wrong since I'm expecting a positive value. I can't figure out where the problem is, I used the same function (with changes in the variables types) to calculate the maximum value an int can contain and it worked...
I though the problem could be caused by comparison inside the if and while statements, hence the typecasting but that didn't help...
Any ideas what is causing this ? Thanks in advance!
EDIT: Thanks to Antti Haapala for his explanations, the overflow to the sign bit results in undefined behavior NOT in negative values.
You can't use calculations like this to deduce the range of signed integers, because signed integer overflow has undefined behaviour, and narrowing conversion at best results in an implementation-defined value, or a signal being raised. The proper solution is to just use SHRT_MAX, INT_MAX ... of <limits.h>. Deducing the maximum value of signed integers via arithmetic is a trick question in standardized C language, and has been so ever since the first standard was published in 1989.
Note that the original edition of K&R predates the standardization of C by 11 years, and even the 2nd one - the "ANSI-C" version predates the finalized standard and differs from it somewhat - they were written for a language that wasn't almost, but not quite, entirely unlike the C language of this day.
You can do it easily for unsigned integers though:
unsigned int i = -1;
// i now holds the maximum value of `unsigned int`.
Per definition, you cannot calculate the maximum value of a type in C, by using variables of that very same type. It simply doesn't make any sense. The type will overflow when it goes "over the top". In case of signed integer overflow, the behavior is undefined, meaning you will get a major bug if you attempt it.
The correct way to do this is to simply check SHRT_MAX from limits.h.
An alternative, somewhat more questionable way would be to create the maximum of an unsigned short and then divide that by 2. We can create the maximum by taking the bitwise inversion of the value 0.
#include <stdio.h>
#include <limits.h>
int main()
{
printf("%hd\n", SHRT_MAX); // best way
unsigned short ushort_max = ~0u;
short short_max = ushort_max / 2;
printf("%hd\n", short_max);
return 0;
}
One note about your code:
Casts such as ((short int)2*i)>(short int)0 are completely superfluous. Most binary operators in C such as * and > implement something called "the usual arithmetic conversions", which is a way to implicitly convert and balance types of an expression. These implicit conversion rules will silently make both of the operands type int despite your casts.
You forgot to cast to short int during comparison
OK, here I assume that the computer would handle integer overflow behavior by changing into negative integers, as I believe that you have assumed in writing this program.
code that outputs 32767:
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
short int max_short(void)
{
short int i = 1, j = 0, k = 0;
while (i>k)
{
k = i;
if (((short int)(2 * i))>(short int)0)
i *= 2;
else
{
j = i;
while ((short int)(i + j) <= (short int)0)
j /= 2;
i += j;
}
}
return i;
}
int main() {
printf("%d", max_short());
while (1);
}
added 2 casts
I know that negative length arrays have undefined behaviours, but with the standard of E1[E2] being identical to (*((E1)+(E2))) I expected something to work.
So in this instance what I do is I create an array that spans in direction -32, so the accessible indexes I expected to gain are -31 up to 0.
I am using 8bit unsigned chars of 0 to 255 and signed chars of -128 to +127, but this happens with 32bit integers and 64bit integers too.
I use C99's ability to declare arrays of variable length to construct the negative spanning array, specifically I am compiling to the GNU99 C standards.
I assign these values to the indexes and print them out as I go, all seems to work fine.
It goes strange when I make a pointer to the value at array index [-31] and then loop through that, 0 to 31, printing the values.
const signed char length = 32;
const signed char negativeLength = -length;
signed char array[negativeLength];
for ( signed char ii = 0; ii > negativeLength; ii-- ) {
array[ii] = ii;
printf( "array %d\n", array[ii] ); /* Prints out expected values */
}
printf( "==========\n" );
signed char * const pointer = &array[negativeLength + 1];
for ( unsigned char ii = 0; ii < length; ii++ ) {
printf( "pointer %d\n", pointer[ii] ); /* Begins printing expected values then goes funky */
}
I get different results every time, but with 32 it generally starts out okay for the first 3 values, it then goes funky and starts printing out -93 up to +47 and then at index pointer[8], array[-23] it goes fine again.
I am running this on an iPad 2.
What exactly is going on here? Is the iPad messing with the pointer or the array when it detects the negative spanning array length?
I sometimes advocate understanding the behavior observed in some C implementations in situations where the C standard does not define the behavior, because it can be illuminating about how certain implementing work or how computers work. In this case, however: Do not do that.
To access an array with arbitrary integer indices, from X (inclusive) to Y (exclusive), do this:
ElementType ArrayMemory[Y-X], *Array = ArrayMemory - X;
If X <= 0 <= Y and X < Y, the behavior of this is defined by the C standard.
Why would you expect something to work when you've done something with undefined behaviour?
While E1[E2] being equivalent to *(E1 + E2) is well defined, the data you're accessing is not well defined so all bets are off.
I'm using a function (Borrowing code from: http://www.exploringbinary.com/converting-floating-point-numbers-to-binary-strings-in-c/) to convert a float into binary; stored in a char. I need to be able to perform bitwise operations on the result though, so I've been trying to find a way to take the string and convert it to an integer so that I can shift the bits around as needed. I've tried atoi() but that seems to return -1.
Thus far, I have:
char binStringRaw[FP2BIN_STRING_MAX];
float myfloat;
printf("Enter a floating point number: ");
scanf("%f", &myfloat);
int castedFloat = (*((int*)&myfloat));
fp2bin(castedFloat, binStringRaw);
Where the input is "12.125", the output of binStringRaw is "10000010100001000000000000000000". However, attempting to perform a bitwise operation on this give an error: "Invalid operands to binary expression ('char[1077]' and 'int')".
P.S. - I apologize if this is a simple question or if there are some general problems with my code. I'm very new to C programming coming from Python.
"castedFloat already is the binary representation of the float, as the cast-operation tells it to interpret the bits of myfloat as bits of an integer instead of a float. "
EDIT: Thanks to Eric Postpischil:
Eric Postpischil in Comments:
"the above is not guaranteed by the C standard. Dereferencing a
converted pointer is not fully specified by the standard. A proper way
to do this is to use a union: int x = (union { float f; int i; }) {
myfloat } .i;. (And one must still ensure that int and float are the
same size in the C implementation being used.)"
Bitwise operations are only defined for Integer-type values, such as char, int, long, ..., thats why it fails when using them on the string (char-array)
btw,
int atoi(char*)
returns the integer-value of a number written inside that string, eg.
atoi("12")
will return an integer with value 12
If you would want to convert the binary representation stored in a string, you have to set the integer bit by bit corresponding to the chars, a function to do this could look like that:
long intFromBinString(char* str){
long ret=0; //initialize returnvalue with zero
int i=0; //stores the current position in string
while(str[i] != 0){ //in c, strings are NULL-terminated, so end of string is 0
ret<<1; //another bit in string, so binary shift resutl-value
if(str[i] == '1') //if the new bit was 1, add that by binary or at the end
ret || 0x01;
i++; //increment position in string
}
return ret; //return result
}
The function fp2bin needs to get a double as parameter. if you call it with castedFloat, the (now interpreted as an integer)value will be implicitly casted to float, and then pass it on.
I assume you want to get a binary representation of the float, play some bitwise ops on it, and then pass it on.
In order to do that you have to cast it back to float, the reverse way you did before, so
int castedFloat = (*((int*)&myfloat));
{/*** some bitwise magic ***/}
float backcastedFloat = (*(float*)&castedFloat);
fp2bin(castedFloat, binStringRaw);
EDIT:(Thanks again, Eric):
union bothType { float f; int i; }) both;
both.f = myfloat;
{/*** some bitwise magic on both.i ***/}
fp2bin(both.f, binStringRaw);
should work