Does scanf modify unmatched corresponding arguments? - scanf

Given the following code and assuming the only input is the letter A followed by a newline, scanf should return 0 due to a matching failure:
int x;
scanf("%d", &x);
My question is whether scanf is legally allowed to alter the value of x even if nothing in the input matches the %d format as long as it still returns 0. The language standard doesn't seem to address this issue so my first impression is that the answer is no.

By careful reading of the standard definition, the function only modifies the pointed values when the scan is successful. scanf("%d %d %d", &a, &b, &c) should not modify b if the return value is less than 2.

Related

char array in c in overflowed scanf operation

I am new to C programming and i am really confused on below code:
#include <stdio.h>
#include <string.h>
int main(void)
{
char arrstr[6];
int i;
printf("Enter: ");
scanf("%s",arrstr);
printf("arrstr is %s\n",arrstr);
printf("length os arrstr is %d\n",strlen(arrstr));
for(i=0;i<20;i++)
{
printf("arrstr[%d] is %c, dec value is %d\n",i,arrstr[i],arrstr[i]);
}
return 0;
}
As from my understanding, after the declaration of arrstr[6], the compiler will allocate 6 bytes for this char array, and consider the last '\0' char, 5 valid chars can be stored in the char array.
But after i run this short code, i get below result:
The printf shows all chars i input, no matter how long is it. But when i using an index to check the array, seems i cannot find the extra chars in the array.
Can anyone helps to explain what happened?
Thanks.
Try changing your code by adding this line right after the scanf statement:
arrstr[5] = '\0';
What has happened is that the null character was overwritten by the user entry. Putting the null character back in manually gives you proper behavior for the next two lines, the printf statements.
The for loop is another matter. C does not have any kind of bounds checking so it's up to the programmer to not overrun the bounds of an array. The values you get after that could be anything at all, as you are just reading uninitialized RAM bytes at that point. A standard way of avoiding this is to use a const int variable to declare the array size:
const int SIZE = 6;
char arrstring[SIZE];
Then also use SIZE as the limit in the for loop.
P.S. There is still a problem here with the user entry as written, because a user could theoretically enter hundreds of characters, and that would get written out-of-bounds it seems, possibly causing weird bugs. There are ways to limit the amount of user entry, but it gets fairly involved, here are some stackoverflow posts on the topic. Keep in mind for future reference:
Limiting user entry with fgets instead of scanf
Cleaning up the stdin stream after using fgets

How to truncate a 2's complement output

I have data written into short data type. The data written is of 2's complement form.
Now when I try to print the data using %04x, the data with MSB=0 is printed fine for eg if data=740, print I get is 0740
But when the MSB=1, I am unable to get a proper print. For eg if data=842, print I get is fffff842
I want the data truncated to 4 bytes so expected output is f842
Either declare your data as a type which is 16 bits long, or make sure the printing function uses the right format for 16 bits value. Or use your current type, but do a bitwise AND with 0xffff. What you can do depends on the language you're doing it in really.
But whichever way you go, check your assumptions again. There seems to be a few issues in your question:
2s-complement applies to signed numbers only. There are no negative numbers in your question.
Assuming you mean C's short - it doesn't have to be 16 bits long.
"I get is fffff842 I want the data truncated to 4 bytes" - fffff842 is 4 bytes long. f842 is 2 bytes long.
2-bytes long value 842 does not have the MSB set.
I'm assuming C (or possibly C++) as the language here.
Because of the default argument promotions involved when calling a variable argument function (such as printf), your use of a short will result in an integer promotion, which states that "If an int can represent all values of the original type (as restricted by the width, for a
bit-field), the value is converted to an int".
A short is converted to an int by means of sign-extension, and 0xf842 sign-extended to 32 bits is 0xfffff842.
You can use a bitwise AND to mask off the most significant word:
printf("%04x", data & 0xffff);
You could also add the h length specifier to state that you only want to print an (unsigned) short worth of bits from an int:
printf("%04hx", data);

SVA - Is there any way to check an variable variable pattern in a variable length serial output using system verilog assertion?

For example, I have a pattern pt=1101 that needs to be checked in a serial output s_out= 1011101110111011 (LSB first). I am trying to check the "pt" in "s_out" only using SVA without using always block. Note: pt and s_out both are variable in length.
I am trying to use two counters for pt and s_out lengths but I don't know how to use them in SVA.
Any suggestions will be much helpful.
Thank you,
susun
You can declare internal variables in sequences and in properties. These can also have input arguments. Here's how I'd approach your problem:
First, I would create a sequence to handle matching one occurrence of the pattern. This sequence would take the pattern as an argument, together with the length:
sequence pattern_in_output(pattern, int unsigned len);
int unsigned count = 0;
(
s_out == pattern[count],
$display("time = ", $time, " count = ", count),
count += 1
) [*len];
endsequence
Notice that the pattern argument is untyped. I also left some debug prints in there for you to see how it works. Once this sequence starts, it checks for len cycles that s_out matches the appropriate bit of the pattern.
I don't know what your exact condition for checking is (when exactly you want to start and stop) so I just assumed you have a signal called tx that tells you if you are currently transmitting or not (1 means you are transmitting so we need to check, 0 means you aren't, hence no check).
The property would look something like this:
assert property (
#(posedge clk)
// check first group
$rose(tx) |-> pattern_in_output(pt, 4)
// if 'tx' is still high, need to check for another occurence
// - repeat this forever
##1 tx |-> pattern_in_output(pt, 4)
// this line causes and internal error
//##1 tx |-> pattern_in_output(pt, 4) [+] or !tx
// this prints when the property exits
##0 (1, $display("exited at ", $time))
);
We start checking on the rising edge of tx. We look for a match of our previously defined sequence. Afterwards, it could be the case that we are still transmitting and we need to check a second occurrence of the pattern. If after this second occurrence, tx is still 1, we need to check for a third and so on.
Here, I'll have to apologize for leaving you with half of an answer. I was doing this example on EDAPlayground and couldn't get this to work (I kept getting simulator internal errors). The line ##1 tx |-> pattern_in_output(pt, 4) only checks for a second occurrence. The one under that (which is commented out), ##1 tx |-> pattern_in_output(pt, 4) [+] or !tx, should check for any subsequent occurrence of the pattern while tx is still 1 and stop matching once it becomes 0.
You'll have to fiddle with the details here yourself, but I guess your question was pretty much answered. You can see how you can use internal variables inside assertion constructs.
P.S. If you want it, the full code (including testing harness) is here: http://www.edaplayground.com/x/4my

Checking the format of a string in Matlab

So I'm reading multiple text files in Matlab that have, in their first columns, a column of "times". These times are either in the format 'MM:SS.milliseconds' (sorry if that's not the proper way to express it) where for example the string '29:59.9' would be (29*60)+(59)+(.9) = 1799.9 seconds, or in the format of straight seconds.milliseconds, where '29.9' would mean 29.9 seconds. The format is the same for a single file, but varies across different files. Since I would like the times to be in the second format, I would like to check if the format of the strings match the first format. If it doesn't match, then convert it, otherwise, continue. The code below is my code to convert, so my question is how do I approach checking the format of the string? In otherwords, I need some condition for an if statement to check if the format is wrong.
%% Modify the textdata to convert time to seconds
timearray = textdata(2:end, 1);
if (timearray(1, 1) %{has format 'MM.SS.millisecond}%)
datev = datevec(timearray);
newtime = (datev(:, 5)*60) + (datev(:, 6));
elseif(timearray(1, 1) %{has format 'SS.millisecond}%)
newtime = timearray;
You can use regular expressions to help you out. Regular expressions are methods of specifying how to search for particular patterns in strings. As such, you want to find if a string follows the formats of either:
xx:xx.x
or:
xx.x
The regular expression syntax for each of these is defined as the following:
^[0-9]+:[0-9]+\.[0-9]+
^[0-9]+\.[0-9]+
Let's step through how each of these work.
For the first one, the ^[0-9]+ means that the string should start with any number (^[0-9]) and the + means that there should be at least one number. As such, 1, 2, ... 10, ... 20, ... etc. is valid syntax for this beginning. After the number should be separated by a :, followed by another sequence of numbers of at least one or more. After, there is a . that separates them, then this is followed by another sequence of numbers. Notice how I used \. to specify the . character. Using . by itself means that the character is a wildcard. This is obviously not what you want, so if you want to specify the actual . character, you need to prepend a \ to the ..
For the second one, it's almost the same as the first one. However, there is no : delimiter, and we only have the . to work with.
To invoke regular expressions, use the regexp command in MATLAB. It is done using:
ind = regexp(str, expression);
str represents the string you want to check, and expression is a regular expression that we talked about above. You need to make sure you encapsulate your expression using single quotes. The regular expression is taken in as a string. ind would this return the starting index of your string of where the match was found. As such, when we search for a particular format, ind should either be 1 indicating that we found this search at the beginning of the string, or it returns empty ([]) if it didn't find a match. Here's a reproducible example for you:
B = {'29:59.9', '29.9', '45:56.8', '24.5'};
for k = 1 : numel(B)
if (regexp(B{k}, '^[0-9]+:[0-9]+\.[0-9]+') == 1)
disp('I''m the first case!');
elseif (regexp(B{k}, '^[0-9]+\.[0-9]+') == 1)
disp('I''m the second case!');
end
end
As such, the code should print out I'm the first case! if it follows the format of the first case, and it should print I'm the second case! if it follows the format of the second case. As such, by running this code, we get:
I'm the first case!
I'm the second case!
I'm the first case!
I'm the second case!
Without knowing how your strings are formatted, I can't do the rest of it for you, but this should be a good start for you.

Error: Can't take log of -9.4351e+0.007

I am creating a mini search engine using Perl.While doing so I am using a formula with log to the base 10. However for some value I am getting an error:
Can't take log of -9.4351e+0.007.
It is impossible to track where I am getting this error from. I just want to ignore this case. How can this be handled in Perl. Subroutine for finding log to the base 10 is like this:
sub log10 {
my $n=shift;
return log($n)/log(10);
}
So probably i am looking for a check which says if so and so value dont find log.
You cannot take the log of negative numbers.
See Wolfram MathWorld for more details.
Apart from the value being negative, the string -9.4351e+0.007 is not a valid number as the exponent part of a floating-point constant can be only an integer.
You must be passing strings to your log10 function as Perl would not complain about a number in this format.
You need to look at the source of these values as something is going wrong before your function is called, and it will probably give you incorrect results even for those values that can be passed to log without error.
"ln y" means "find the x where ex equals y".
e is a positive number (near 2.17828), so no matter how many times you multiply e with itself, you'll never get a negative number.
You cannot find the log of negative numbers.
As Borodin also points out that -9.4351e+0.007 isn't recognized as a number by Perl.
>perl -wE"say 0+'-9.4351e+0.007'"
Argument "-9.4351e+0.007" isn't numeric in addition (+) at -e line 1.
-9.4351