473,388 Members | 1,286 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,388 software developers and data experts.

Using strtod

Hi experts,
Is the following usage of strtod okay (p is a char pointer):

value = strtod(p, &p);

Is it possible that this would evoke undefined behaviour?
Or should I use a temporary pointer and then assign its value to p?

Thanks

Feb 18 '07 #1
18 2422
coder wrote:
Hi experts,
Is the following usage of strtod okay (p is a char pointer):

value = strtod(p, &p);

Is it possible that this would evoke undefined behaviour?
Or should I use a temporary pointer and then assign its value to p?
You are allowed to do this as long as you bypass any possible macro
definition of strtod:

value = (strtod) (p, &p);

But it would be cleaner to just use a temporary.

Feb 18 '07 #2
On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
<snip>
Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);
I didn't get that. Can you please explain a little more?
But it would be cleaner to just use a temporary.

Feb 18 '07 #3
coder wrote:
Hi experts,
Is the following usage of strtod okay (p is a char pointer):

value = strtod(p, &p);

Is it possible that this would evoke undefined behaviour?
Or should I use a temporary pointer and then assign its value to p?
You should use a temporary, not because of undefined
behavior (but see Harald van Dijk's response), but because
you will need the original pointer's value when you check
for errors. After strtod(p, &q), the condition p==q means
strtod() was unable to convert any of the input. If you
write strtod(p, &p) you will be unable to make the test.

--
Eric Sosman
es*****@acm-dot-org.invalid
Feb 18 '07 #4
coder wrote:
On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
<snip>

Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);

I didn't get that. Can you please explain a little more?
strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.

Feb 18 '07 #5
coder wrote:
>
Is the following usage of strtod okay (p is a char pointer):

value = strtod(p, &p);

Is it possible that this would evoke undefined behaviour? Or
should I use a temporary pointer and then assign its value to p?
Why not read the description of the function? Note the
'restrict'. From N869:

7.20.1.3 The strtod, strtof, and strtold functions

Synopsis

[#1]
#include <stdlib.h>
double strtod(const char * restrict nptr,
char ** restrict endptr);
float strtof(const char * restrict nptr,
char ** restrict endptr);
long double strtold(const char * restrict nptr,
char ** restrict endptr);

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews

Feb 18 '07 #6
CBFalconer wrote:
coder wrote:

Is the following usage of strtod okay (p is a char pointer):

value = strtod(p, &p);

Is it possible that this would evoke undefined behaviour? Or
should I use a temporary pointer and then assign its value to p?

Why not read the description of the function? Note the
'restrict'. From N869:

7.20.1.3 The strtod, strtof, and strtold functions

Synopsis

[#1]
#include <stdlib.h>
double strtod(const char * restrict nptr,
char ** restrict endptr);
float strtof(const char * restrict nptr,
char ** restrict endptr);
long double strtold(const char * restrict nptr,
char ** restrict endptr);
I'm pretty sure restrict is irrelevant here. It means the behaviour's
undefined if you do

char *p;
// ...
strtod((char *) &p, &p);

which could otherwise be defined, but it says nothing about

char *p;
// ...
strtod(p, &p);

Feb 18 '07 #7
On 18 Feb 2007 10:54:18 -0800, "Harald van D?k" <tr*****@gmail.com>
wrote in comp.lang.c:
coder wrote:
On Feb 18, 10:47 pm, "Harald van D?k" <true...@gmail.comwrote:
coder wrote:
<snip>
Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);
I didn't get that. Can you please explain a little more?

strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.
Chapter and verse, please.

There is nothing at all in the standard that states that strtod() or
the other related strto... functions do not write to the pointer
addressed by their second argument until after they have finished all
use of the first argument.

You may say that were you to implement such a function, you would not
store the pointer value until you were finished with all other
processing. You may say that there is no need for any reasonable
implementation of strtod() to do so.

But unless you can point to wording in the standard that states this,
your answer is wrong and the OP's code produces undefined behavior.

There is absolutely nothing at all preventing an implementation from
providing a strtod() function like this:

double strtod(const char * restrict nptr, char ** restrict endptr)
{
double result = 0.0;
*endptr = NULL;

while (*nptr++ != '\0')
{
/* processing */
}
*endptr = nptr;
}

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Feb 19 '07 #8
In article <5s********************************@4ax.com>,
Jack Klein <ja*******@spamcop.netwrote:
>On 18 Feb 2007 10:54:18 -0800, "Harald van D?k" <tr*****@gmail.com>
wrote in comp.lang.c:
>strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write.
>Chapter and verse, please.
There is a sequence point after evaluation of the arguments
to a function, but before the function is called. Copies of the
value of the arguments are passed, not pass by reference.

Therefore, strtod(p,&p) would have to read p and calculate the
address of p, saving the read value and the address (reading
and saving done in any order); then the sequence point
requirement requires that the read and address calculation be
completed and the copies fully saved before the function is
invoked. The function would receive a value in the first
parameter that -happened- to contain the same contents as
could be found by dereferencing the pointer in the second
argument at that time, but there would be no way for the
function body to write into the pointer before that value-
copy had been taken because of the sequence point.

But as Harald pointed out, the sequence point requirements do
not apply to macros, so implementing as a macro could have different
results.
--
"No one has the right to destroy another person's belief by
demanding empirical evidence." -- Ann Landers
Feb 19 '07 #9
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);

I didn't get that. Can you please explain a little more?

strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.

Chapter and verse, please.

There is nothing at all in the standard that states that strtod() or
the other related strto... functions do not write to the pointer
addressed by their second argument until after they have finished all
use of the first argument.
C uses pass by value. If you pass the value of p as the first
argument and the address of p as the second argument, these values
are determined at the sequence point after argument evaluation but
before the call of the function. The value of the first argument
(pointer) cannot be changed by subsequent alteration of the pointer
pointed at by the second argument.

strtod() may read the value of the string pointed at by its first
argument. strtod() may modify the pointer pointed at by its second
argument, but it is not supposed to read the string originally
pointed at by the character pointer pointed at by the second argument.
(You're allowed to pass &p for an uninitialized pointer p). Since
there is no overlap between what's read through the first argument
and what's read or written through the second, there's no problem.
>You may say that were you to implement such a function, you would not
store the pointer value until you were finished with all other
processing. You may say that there is no need for any reasonable
implementation of strtod() to do so.
It may do so, and it doesn't matter.
>But unless you can point to wording in the standard that states this,
your answer is wrong and the OP's code produces undefined behavior.

There is absolutely nothing at all preventing an implementation from
providing a strtod() function like this:

double strtod(const char * restrict nptr, char ** restrict endptr)
{
double result = 0.0;
*endptr = NULL;
The above statement cannot mess up nptr nor what it points at.
>
while (*nptr++ != '\0')
{
/* processing */
}
*endptr = nptr;
}
Feb 19 '07 #10
On Feb 18, 11:54 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
<snip>
Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);
I didn't get that. Can you please explain a little more?

strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.
I still don't understand fully. Can you (or someone else) please give
an example to illustrate this?

Please excuse me for my ignorance.

Feb 19 '07 #11
Gordon Burditt wrote:
>
>>>>You are allowed to do this as long as you bypass any possible
macro definition of strtod:
>
value = (strtod) (p, &p);

I didn't get that. Can you please explain a little more?

strtod(p, &p) both reads from p and writes to p. If you're using
a function, there's no problem, because the reading from p is
guaranteed to take place before any write. If you're using a
macro, the macro is allowed to write to p before reading its
original value.

Chapter and verse, please.

There is nothing at all in the standard that states that strtod()
or the other related strto... functions do not write to the
pointer addressed by their second argument until after they have
finished all use of the first argument.
.... snip ...
>>
There is absolutely nothing at all preventing an implementation
from providing a strtod() function like this:

double strtod(const char * restrict nptr, char ** restrict endptr)
{
double result = 0.0;
*endptr = NULL;

The above statement cannot mess up nptr nor what it points at.
However something like (never mind if it is an accurate strtod)

double strtod(const char *restrict nptr, char* *restrict endptr)
{
if (*nptr) {
do {
**nptr = '0';
} while (*(*nptr)++ != '\0');
}
return 0.0;
}

can foul everything up nicely as a result of ignoring restrict.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Feb 19 '07 #12
coder wrote:
On Feb 18, 11:54 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
<snip>
Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);
I didn't get that. Can you please explain a little more?
strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.

I still don't understand fully. Can you (or someone else) please give
an example to illustrate this?

Please excuse me for my ignorance.
Let's use strtol as another example for simplicity, and let's say the
compiler supports GCC-style statement-expressions and C++-style
references as extensions. Then, strtol might be implemented as
something similar to

#define strtol(n, end, base) \
({ \
const char * const &__n = n; \
char * &__end = *end; \
int const &__base = base; \
for (__end = __n; *__end != '\0'; __end++) \
if (!isspace(*__end)) \
break; \
for (; *__end != '\0'; __end++) \
if (!isbasedigit(*__end, __base)) \
break; \
strntol(__n, __end - __n, __base); \
})

Consider what would happen when end == &n: the final call to strntol
(a non-standard helper function) would pass unexpected arguments.

(Note: this example would need some editing to even be a potential
valid implementation of strtol, but the basic idea stands.)

Feb 19 '07 #13
CBFalconer wrote:
Gordon Burditt wrote:
>>>You are allowed to do this as long as you bypass any possible
macro definition of strtod:

value = (strtod) (p, &p);

I didn't get that. Can you please explain a little more?

strtod(p, &p) both reads from p and writes to p. If you're using
a function, there's no problem, because the reading from p is
guaranteed to take place before any write. If you're using a
macro, the macro is allowed to write to p before reading its
original value.

Chapter and verse, please.

There is nothing at all in the standard that states that strtod()
or the other related strto... functions do not write to the
pointer addressed by their second argument until after they have
finished all use of the first argument.
... snip ...
>
There is absolutely nothing at all preventing an implementation
from providing a strtod() function like this:

double strtod(const char * restrict nptr, char ** restrict endptr)
{
double result = 0.0;
*endptr = NULL;
The above statement cannot mess up nptr nor what it points at.

However something like (never mind if it is an accurate strtod)

double strtod(const char *restrict nptr, char* *restrict endptr)
{
if (*nptr) {
do {
**nptr = '0';
} while (*(*nptr)++ != '\0');
}
return 0.0;
}

can foul everything up nicely as a result of ignoring restrict.
How can you assign to **nptr when nptr is a pointer to a character?

Feb 19 '07 #14
>>>>>You are allowed to do this as long as you bypass any possible
>>>>>macro definition of strtod:
>>
>value = (strtod) (p, &p);
>
I didn't get that. Can you please explain a little more?

strtod(p, &p) both reads from p and writes to p. If you're using
a function, there's no problem, because the reading from p is
guaranteed to take place before any write. If you're using a
macro, the macro is allowed to write to p before reading its
original value.

Chapter and verse, please.

There is nothing at all in the standard that states that strtod()
or the other related strto... functions do not write to the
pointer addressed by their second argument until after they have
finished all use of the first argument.
... snip ...
>>>
There is absolutely nothing at all preventing an implementation
from providing a strtod() function like this:

double strtod(const char * restrict nptr, char ** restrict endptr)
{
double result = 0.0;
*endptr = NULL;

The above statement cannot mess up nptr nor what it points at.

However something like (never mind if it is an accurate strtod)

double strtod(const char *restrict nptr, char* *restrict endptr)
{
if (*nptr) {
do {
**nptr = '0';
How can you double-dereference a const char *restrict pointer?
This shouldn't even compile.
} while (*(*nptr)++ != '\0');
}
return 0.0;
}
If you really meant endptr rather than nptr in the above code,
you are dereferencing a pointer (*endptr) that is permitted to
be uninitialized and is supposed to be write-only.
>can foul everything up nicely as a result of ignoring restrict.
It's got a lot more problems than just ignoring restrict.

Feb 19 '07 #15
On Feb 19, 12:15 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 11:54 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
<snip>
Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);
I didn't get that. Can you please explain a little more?
strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.
I still don't understand fully. Can you (or someone else) please give
an example to illustrate this?
Please excuse me for my ignorance.

Let's use strtol as another example for simplicity, and let's say the
compiler supports GCC-style statement-expressions and C++-style
references as extensions. Then, strtol might be implemented as
something similar to

#define strtol(n, end, base) \
({ \
const char * const &__n = n; \
char * &__end = *end; \
int const &__base = base; \
for (__end = __n; *__end != '\0'; __end++) \
if (!isspace(*__end)) \
break; \
for (; *__end != '\0'; __end++) \
if (!isbasedigit(*__end, __base)) \
break; \
strntol(__n, __end - __n, __base); \
})

Consider what would happen when end == &n: the final call to strntol
(a non-standard helper function) would pass unexpected arguments.

(Note: this example would need some editing to even be a potential
valid implementation of strtol, but the basic idea stands.)
Ok, so the basic idea is that a macro can access variables directly,
whereas variables are passed by value to functions. Is that right?

Feb 19 '07 #16
coder wrote:
On Feb 19, 12:15 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 11:54 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
<snip>
Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possible macro
definition of strtod:
value = (strtod) (p, &p);
I didn't get that. Can you please explain a little more?
strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.
I still don't understand fully. Can you (or someone else) please give
an example to illustrate this?
Please excuse me for my ignorance.
Let's use strtol as another example for simplicity, and let's say the
compiler supports GCC-style statement-expressions and C++-style
references as extensions. Then, strtol might be implemented as
something similar to

#define strtol(n, end, base) \
({ \
const char * const &__n = n; \
char * &__end = *end; \
int const &__base = base; \
for (__end = __n; *__end != '\0'; __end++) \
if (!isspace(*__end)) \
break; \
for (; *__end != '\0'; __end++) \
if (!isbasedigit(*__end, __base)) \
break; \
strntol(__n, __end - __n, __base); \
})

Consider what would happen when end == &n: the final call to strntol
(a non-standard helper function) would pass unexpected arguments.

(Note: this example would need some editing to even be a potential
valid implementation of strtol, but the basic idea stands.)

Ok, so the basic idea is that a macro can access variables directly,
whereas variables are passed by value to functions. Is that right?
That may be a bit oversimplified, but it's the basic idea, yes.

Feb 19 '07 #17
On Feb 19, 1:54 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 19, 12:15 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 11:54 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
On Feb 18, 10:47 pm, "Harald van Dijk" <true...@gmail.comwrote:
coder wrote:
<snip>
Thanks for the reply, Harald.
You are allowed to do this as long as you bypass any possiblemacro
definition of strtod:
value = (strtod) (p, &p);
I didn't get that. Can you please explain a little more?
strtod(p, &p) both reads from p and writes to p. If you're using a
function, there's no problem, because the reading from p is guaranteed
to take place before any write. If you're using a macro, the macro is
allowed to write to p before reading its original value.
I still don't understand fully. Can you (or someone else) please give
an example to illustrate this?
Please excuse me for my ignorance.
Let's use strtol as another example for simplicity, and let's say the
compiler supports GCC-style statement-expressions and C++-style
references as extensions. Then, strtol might be implemented as
something similar to
#define strtol(n, end, base) \
({ \
const char * const &__n = n; \
char * &__end = *end; \
int const &__base = base; \
for (__end = __n; *__end != '\0'; __end++) \
if (!isspace(*__end)) \
break; \
for (; *__end != '\0'; __end++) \
if (!isbasedigit(*__end, __base)) \
break; \
strntol(__n, __end - __n, __base); \
})
Consider what would happen when end == &n: the final call to strntol
(a non-standard helper function) would pass unexpected arguments.
(Note: this example would need some editing to even be a potential
valid implementation of strtol, but the basic idea stands.)
Ok, so the basic idea is that a macro can access variables directly,
whereas variables are passed by value to functions. Is that right?

That may be a bit oversimplified, but it's the basic idea, yes.
Thanks for the information, Harald.

Feb 19 '07 #18
Harald van D?k wrote:
CBFalconer wrote:
>Gordon Burditt wrote:
>>>
>>You are allowed to do this as long as you bypass any possible
>>macro definition of strtod:
>>>
>>value = (strtod) (p, &p);
>>
>I didn't get that. Can you please explain a little more?
>
strtod(p, &p) both reads from p and writes to p. If you're using
a function, there's no problem, because the reading from p is
guaranteed to take place before any write. If you're using a
macro, the macro is allowed to write to p before reading its
original value.

Chapter and verse, please.

There is nothing at all in the standard that states that strtod()
or the other related strto... functions do not write to the
pointer addressed by their second argument until after they have
finished all use of the first argument.
... snip ...
>>>>
There is absolutely nothing at all preventing an implementation
from providing a strtod() function like this:

double strtod(const char * restrict nptr, char ** restrict endptr)
{
double result = 0.0;
*endptr = NULL;

The above statement cannot mess up nptr nor what it points at.

However something like (never mind if it is an accurate strtod)

double strtod(const char *restrict nptr, char* *restrict endptr)
{
if (*nptr) {
do {
**nptr = '0';
} while (*(*nptr)++ != '\0');
}
return 0.0;
}

can foul everything up nicely as a result of ignoring restrict.

How can you assign to **nptr when nptr is a pointer to a character?
Woops. Replace nptr with endptr in the above fragment body.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Feb 20 '07 #19

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Mathieu Malaterre | last post by:
Hello, I would like to have some advices on this problem I am having. In my code I have hardcoded a string like: const char foo = "11 0.438482 "; I was then calling strtod to transform it...
21
by: Marky C | last post by:
atof is not working. double a = atof("12.345"); a gets set to 12.000 I am working on a toshiba micro. The data map has no space allocated to it for dynamic memory. Does anyone have an...
9
by: Adam Warner | last post by:
Hi all, Message ID <c1qo3f0tro@enews2.newsguy.com> is one of many informative articles by Chris Torek about C. The particular message discusses aliasing and concludes with this paragraph: ...
4
by: Gary Wessle | last post by:
Hi I have a vector<stringwhich holds numbers, I need to loop and printout those numbers + a value as doubles . typedef vector<string>::const_iterator vs_itr; for(vs_itr i=vect.begin();...
8
by: Bill Cunningham | last post by:
Since I've been told that char *argv or char **argv must be the second parameter to main's command line structure I have turned to strtod( ) but can't get it to work so far. This function is...
4
by: Bob Nelson | last post by:
Fellow C pushers: Deliberately avoiding a look at Jack Klein's bulletproof code for a robust use of strtol(), I respectfully submit the following for review and vigorous critique, desiring...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.