473,626 Members | 3,340 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

ANSI C question about 'volatile'

I have a question about what ANSI C allows/requires in a particular
context related to 'volatile'. Consider the following:

volatile int x;

int
x_remainder_arg ( int y ){
return x % y;
}

Suppose we had a machine that doesn't have a remainder
instruction and the compiler implements remainder using
the re-writing

a % b :=: a - a/b*b

Let's assume for the sake of discussion that the identity
is ok in the value sense - so if 'a' and 'b' are values,
the expression on the right hand side yields the correct
value. My question is how does 'x' being 'volatile' affect
things? For example, if 'x_remainder_ar g' were compiled
as though it were written like this (and no optimization):

int
x_remainder_arg _1( int y ){
int t = x;
return t - t/y*y;
}

that seems alright. But what if 'x_remainder_ar g' were
compiled as though it were written like this:

int
x_remainder_arg _2( int y ){
return x - x/y*y;
}

Note that 'x', which is 'volatile', is referenced only
once in the original function, but has two references
in the compiled code.

Now for my questions:

1) Does the ANSI C standard _permit_ an interpretation
like 'x_remainder_ar g_2' where two references to 'x'
are made in the compiled code when only one reference
to 'x' is made in the source? If so, why?

2) Does the ANSI C standard _forbid_ an interpretation
like 'x_remainder_ar g_2' where two references to 'x'
are made in the compiled code when only one reference
to 'x' is made in the source? If so, why?
Please note that I am not asking what the compiler
ought to do, or what the standard ought to permit
or to forbid. I'm asking only what the standard
does permit or does forbid.

If different versions of the ANSI standard say different
things on these questions I'd like to know that too.
Please identify which version is being referenced if
that's relevant.

thanks!

Nov 14 '05 #1
9 2756
On 12 Aug 2004 19:55:43 -0700, Tim Rentsch <tx*@alumnus.ca ltech.edu>
wrote in comp.lang.c:
I have a question about what ANSI C allows/requires in a particular
context related to 'volatile'. Consider the following:

volatile int x;

int
x_remainder_arg ( int y ){
return x % y;
}

Suppose we had a machine that doesn't have a remainder
instruction and the compiler implements remainder using
the re-writing

a % b :=: a - a/b*b

Let's assume for the sake of discussion that the identity
is ok in the value sense - so if 'a' and 'b' are values,
the expression on the right hand side yields the correct
value. My question is how does 'x' being 'volatile' affect
things? For example, if 'x_remainder_ar g' were compiled
as though it were written like this (and no optimization):

int
x_remainder_arg _1( int y ){
int t = x;
return t - t/y*y;
}

that seems alright. But what if 'x_remainder_ar g' were
compiled as though it were written like this:

int
x_remainder_arg _2( int y ){
return x - x/y*y;
}

Note that 'x', which is 'volatile', is referenced only
once in the original function, but has two references
in the compiled code.

Now for my questions:

1) Does the ANSI C standard _permit_ an interpretation
like 'x_remainder_ar g_2' where two references to 'x'
are made in the compiled code when only one reference
to 'x' is made in the source? If so, why?
No.
2) Does the ANSI C standard _forbid_ an interpretation
like 'x_remainder_ar g_2' where two references to 'x'
are made in the compiled code when only one reference
to 'x' is made in the source? If so, why?
Yes.
Please note that I am not asking what the compiler
ought to do, or what the standard ought to permit
or to forbid. I'm asking only what the standard
does permit or does forbid.

If different versions of the ANSI standard say different
things on these questions I'd like to know that too.
Please identify which version is being referenced if
that's relevant.

thanks!


Your "If so, why?" questions have to do with the rationale, which is
not part of the standard. Unless you are happy with the answer
"because the standard says so". All versions of the standard.

On the other hand, if you want references to portions of the standard,
here are some from the current (1999) version:

Definition of the volatile type qualifier, 6.7.3 paragraph 6:

"An object that has volatile-qualified type may be modified in ways
unknown to the implementation or have other unknown side effects.
Therefore any expression referring to such an object shall be
evaluated strictly according to the rules of the abstract machine,
as described in 5.1.2.3."

And 5.1.2.3 paragraph 3:

"In the abstract machine, all expressions are evaluated as specified
by the semantics."

Since the semantics of the source code specify that the function
accesses the object exactly once, a conforming implementation may not
access a volatile object more or less than once.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #2
Jack Klein <ja*******@spam cop.net> writes:
Your "If so, why?" questions have to do with the rationale, which is
not part of the standard. Unless you are happy with the answer
"because the standard says so". All versions of the standard.
Sorry I was unclear on this. What I meant was "what is your
reasoning?" (which you addressed following...)

On the other hand, if you want references to portions of the standard,
here are some from the current (1999) version:

Definition of the volatile type qualifier, 6.7.3 paragraph 6:

"An object that has volatile-qualified type may be modified in ways
unknown to the implementation or have other unknown side effects.
Therefore any expression referring to such an object shall be
evaluated strictly according to the rules of the abstract machine,
as described in 5.1.2.3."

And 5.1.2.3 paragraph 3:

"In the abstract machine, all expressions are evaluated as specified
by the semantics."
I saw these paragraphs (or something very much like them). What
I did not see was a clear statement about what the semantics
implied in the case of volatile. I looked! Maybe I overlooked
something, but I didn't see any clear statement about what the
semantics specify (do you have a section reference?). Hence
my questions.
Since the semantics of the source code specify that the function
accesses the object exactly once, a conforming implementation may not
access a volatile object more or less than once.


This piece is what I'm missing - where is the statement of "what
the semantics specify"?

thanks!
Nov 14 '05 #3
In article <ga************ *************** *****@4ax.com>
Jack Klein <ja*******@spam cop.net> writes:
Since the semantics of the source code specify that the function
accesses the object exactly once, a conforming implementation may not
access a volatile object more or less than once.


On the other hand, the same C Standard says:

... What constitutes an access to an object that has
volatile-qualified type is implementation-defined.

which leaves the implementor a truck-sized loophole: he can simply
define away all but one of the actual memory references, leaving
only one of them as an "access".

I would encourage people not to buy such an implementation, though. :-)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #4
Tim Rentsch wrote:
Jack Klein <ja*******@spam cop.net> writes:
.... snip ...

Definition of the volatile type qualifier, 6.7.3 paragraph 6:
.... snip ...
as described in 5.1.2.3."

And 5.1.2.3 paragraph 3:

.... snip ...
I saw these paragraphs (or something very much like them). What
I did not see was a clear statement about what the semantics
implied in the case of volatile. I looked! Maybe I overlooked
something, but I didn't see any clear statement about what the
semantics specify (do you have a section reference?). Hence
my questions.


I think you need to take Richard Heathfields course on "Reading
for Comprehension".

--
Chuck F (cb********@yah oo.com) (cb********@wor ldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home .att.net> USE worldnet address!

Nov 14 '05 #5
Chris Torek wrote:
In article <ga************ *************** *****@4ax.com>
Jack Klein <ja*******@spam cop.net> writes:
Since the semantics of the source code specify that the function
accesses the object exactly once, a conforming implementation may not
access a volatile object more or less than once.

On the other hand, the same C Standard says:

... What constitutes an access to an object that has
volatile-qualified type is implementation-defined.

which leaves the implementor a truck-sized loophole: he can simply
define away all but one of the actual memory references, leaving
only one of them as an "access".

I would encourage people not to buy such an implementation, though. :-)


Hard to avoid such gaps, I think.

struct s {
double trouble;
char coal[2048];
long long way_to_tipperar y;
};
volatile struct s s1;
struct s s2;
...
s2 = s1;

Most implementations , I think, would be forced to define the
single C-level "access" to `s1' in terms of multiple hardware-
level "accesses."

--
Er*********@sun .com

Nov 14 '05 #6
Eric Sosman <Er*********@su n.com> wrote in message news:<41******* *******@sun.com >...
Chris Torek wrote:
In article <ga************ *************** *****@4ax.com>
Jack Klein <ja*******@spam cop.net> writes:
Since the semantics of the source code specify that the function
accesses the object exactly once, a conforming implementation may not
access a volatile object more or less than once.

On the other hand, the same C Standard says:

... What constitutes an access to an object that has
volatile-qualified type is implementation-defined.

which leaves the implementor a truck-sized loophole: he can simply
define away all but one of the actual memory references, leaving
only one of them as an "access".

I would encourage people not to buy such an implementation, though. :-)


Hard to avoid such gaps, I think.

struct s {
double trouble;
char coal[2048];
long long way_to_tipperar y;
};
volatile struct s s1;
struct s s2;
...
s2 = s1;

Most implementations , I think, would be forced to define the
single C-level "access" to `s1' in terms of multiple hardware-
level "accesses."


this begs the question, what in the world is multiple hardware-level
accesses? and how does this affect something volatile?
Nov 14 '05 #7
j0mbolar wrote:
Eric Sosman <Er*********@su n.com> wrote in message news:<41******* *******@sun.com >...
Chris Torek wrote:
In article <ga************ *************** *****@4ax.com>
Jack Klein <ja*******@spam cop.net> writes:
Since the semantics of the source code specify that the function
accesses the object exactly once, a conforming implementation may not
access a volatile object more or less than once.
On the other hand, the same C Standard says:

... What constitutes an access to an object that has
volatile-qualified type is implementation-defined.

which leaves the implementor a truck-sized loophole: he can simply
define away all but one of the actual memory references, leaving
only one of them as an "access".

I would encourage people not to buy such an implementation, though. :-)


Hard to avoid such gaps, I think.

struct s {
double trouble;
char coal[2048];
long long way_to_tipperar y;
};
volatile struct s s1;
struct s s2;
...
s2 = s1;

Most implementations , I think, would be forced to define the
single C-level "access" to `s1' in terms of multiple hardware-
level "accesses."

this begs the question, what in the world is multiple hardware-level
accesses? and how does this affect something volatile?


Implementation-defined, of course. ;-)

Suppose some particular platform implements the above as
2064 byte-to-byte copies. Another might implement it as 516
word-to-word copies, and still another as 258 longword-to-
longword copies. The 2064 or 516 or 258 fetches are the
"hardware-level accesses" to the volatile object. No machine
I'm aware of can do the whole job with just one fetch, so
`volatile' cannot require it to do so.

What are the consequences? Well, the intent of `volatile'
is to inform the compiler that an object's value might change
in ways the compiler cannot discover[*]. So let's suppose that
there's some agency "out there" that occasionally changes the
contents of `s1'. If the change occurs when the copy has
performed only the first 100 of its fetches, what ends up in
`s2' is anyone's guess. `volatile' cannot imply atomicity.
[*] Or to tell it that apparently useless assignments to
the variable are important. For example, in code
like `s1.trouble = 0.0; s1.trouble = 42.0;' the
first assignment must not be optimized away.

--
Er*********@sun .com

Nov 14 '05 #8
>> Chris Torek wrote:
> ... the same C Standard says:
> ... What constitutes an access to an object that has
> volatile-qualified type is implementation-defined.
> which leaves the implementor a truck-sized loophole: he can simply
> define away all but one of the actual memory references, leaving
> only one of them as an "access".
Eric Sosman <Er*********@su n.com> wrote in message
news:<41****** ********@sun.co m>...
Hard to avoid such gaps, I think.
[example snipped, but it includes a large structure assignment] Most implementations , I think, would be forced to define the
single C-level "access" to `s1' in terms of multiple hardware-
level "accesses."


Indeed.

In article <news:2d******* *************** **@posting.goog le.com>
j0mbolar <j0******@engin eer.com> asked:this begs the question, what in the world is multiple hardware-level
accesses? and how does this affect something volatile?


The *intent* of the C Standard is clear: the hardware has some
set(s) of instruction(s) that perform hardware-level access, and
there is some mapping from "hardware access" to "C code". That
mapping is allowed to be optimized as much as possible *except*
in the presence of "volatile" qualifiers, where the mapping should
be as direct as possible.

Suppose we have a conventional load/store architecture, for instance,
in which there are only "two kinds" of "hardware access": the "load"
and the "store". In assembly these are achieved via "ld" and "st"
instructions. Only one "bus width" is supported (the 32-bit-word),
so that:

ld r1,(r2)
st r1,(r3)

"means": "do a 32-bit bus access to the address given by r2, putting
the value retrieved into r1; then do a 32-bit bus access to the
address given by r3, storing the value now in r1".

Hardware *devices* may then respond in particular (and peculiar)
ways to these two hardware-level bus transactions.

Since the C compiler for this particular machine has 32-bit "int"s,
we can do the same in C with:

int r1;
volatile int *r2, *r3;
r1 = *r2;
*r3 = r1;

and "expect" the C compiler to generate the "obvious" code (although
the register numbers might change in the process). The C Standard
gives us (C programmers) "volatile" to do it, but does not promise
us that the compiler will accede to our wishes; it is up to us to
obtain a C compiler that actually does so.

What happens, though, if we have a 16-bit or 8-bit hardware device
and have to connect it to this machine? The *machine* is PHYSICALLY
INCAPABLE of doing anything other than a 32-bit-wide access. How
can we take an AMD "Lance" Ethernet device, with its two 16-bit
registers, and make it work with this (MIPS-R2000-like) CPU?

The answer in this case was to put the 16-bit registers on 32-bit
boundaries:

struct lance_registers {
uint16_t pad1;
uint16_t rap; /* Register Address Port */
uint16_t pad2;
uint16_t rdp; /* Register Data Port */
}; /* (I might have the address and data ports backwards) */

This, however, is *not* how it is done on a conventional 80x86-like
CPU, which *does* have multiple different bus-size-transactions.
Here the compiler should use 16-bit bus accesses for 16-bit integers,
and 8-bit bus accesses for 8-bit integers, and the two "pad"s go
away in the structure.

Moreover, the 80x86 has what are called "read-modify-write" bus
cycles, as did the PDP-11 and VAX. Some PDP-11 Unibus hardware
devices *required* certain operations to use these r/m/w cycles
to obtain predictable results. To get such a bus cycle, an assembler
programmer might use the "bis" or "bic" instructions on the VAX:

bisw2 r1,(r6)

This instruction reads from the (presumably Unibus) location given
by r6, sets the bits given by r1, and writes the result back, all
within a single bus operation using the "r/m/w" cycle. The C programmer
familiar with all this would write the code as:

*r6 |= r1;

and "expect" to get the same bisw2 instruction (provided r6 has
type "volatile unsigned short *" or similar). Writing:

*r6 = *r6 | r1;

would instead produce an assembler sequence like:

movzwl (r6),r0 # or perhaps just movw
bisl2 r1,r0 # in which case this would be a bisw2
movw r0,(r6)

Again, while "volatile" is *necessary* to tell the compiler "please
do not attempt to optimize this", it is not *sufficient* -- the
compilre must actually generate different code for the "|=" operation.
A similer compiler on a load/store architecture *cannot* generate
a single instruction for this, though, because there IS NO SUCH
SINGLE INSTRUCTION (and there are no r/m/w bus cycles).

The answers to j0mbolar's questions, then, are: "access" is really
defined by the hardware, and as C programmers, we have to know not
only what the hardware does, but also whether we can convince our
C compilers to generate the necessary code. When C's types and
operations "map nicely" onto the hardware, we can expect, and should
really demand, that our C compilers do the "obvious thing".

What about the cases where C's types and operations do not fit well
with the hardware-level operations? Consider the V8 SPARC's "ldstub"
(load/store unsigned byte) instruction, or V9's compare and swap;
the 80x86 compare-and-exchange instructions; and the MIPS and PowerPC
style "load linked / store conditional" pairs. The ldstub
instruction is defined as an atomic bus cycle that:

- reads a byte from memory
- stores 0xff into memory

and gives you the original byte in the register. If two devices
or processors attempt this at the "same time", and the byte is
originally not 0xff, one of them will "see" the original byte and
the other will see the 0xff. The compare and swap (aka compare
and exchange) instructions, which are more powerful, take two
registers and a memory location and atomically:

- compare the first register with the memory value
- if they are equal, change the memory value to the second register,
but if they are not equal, leave the memory value alone
- leave the result of the comparison or the original memory value
(or both) in one of the registers and/or in some condition codes

The ll/sc sequence, which is perhaps the most powerful of all,
loads a value from memory into a register, and then later stores
a new value (as given by a register) into that memory location but
only if no one else has changed it yet. (This is done through the
cache protocols -- the CPU cache uses MESI or MOESI to cooperate
with other devices, and is alerted if the value gets changed between
the two separate instructions. While CAS can be used to implement
atomic adds and mutexes, LL+SC can be used to implement atomic
queues.)

The closest one can come to writing CAS in C, for instance, is:

tmp = *mem;
if (tmp == r1)
*mem = r2;
r1 = tmp;

but all this happens in a single bus cycle. There is no C operator
that compresses this down to one operation. The LL/SC sequence
actually takes multiple bus cycles and cannot be expressed at all
in C.

Today, the usual tack for handling the "cannot be written in C at
all" instructions is to use assembly code -- either a C-callable
subroutine, or inline expansion.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #9
On 13 Aug 2004 03:53:46 GMT, Chris Torek <no****@torek.n et> wrote in
comp.lang.c:
In article <ga************ *************** *****@4ax.com>
Jack Klein <ja*******@spam cop.net> writes:
Since the semantics of the source code specify that the function
accesses the object exactly once, a conforming implementation may not
access a volatile object more or less than once.


On the other hand, the same C Standard says:

... What constitutes an access to an object that has
volatile-qualified type is implementation-defined.

which leaves the implementor a truck-sized loophole: he can simply
define away all but one of the actual memory references, leaving
only one of them as an "access".

I would encourage people not to buy such an implementation, though. :-)


But surely you know, as you posted later on in this thread, that this
is really only an artifact of a poor choice of wording in the
standard, as has been discussed, without a satisfactory conclusion, in
comp.std.c.

You yourself bring up the issue of a number of relatively small sized
volatile objects sharing a single bus-width address. And there is the
opposite example, for example a 16-bit wide volatile object addressed
over an 8-bit bus. Indeed, a volatile int (minimum 16 bits) will
always require two bus cycles to read on an 8051 family derivative.

But no compiler worth its salt could wiggle out of making multiple
accesses to free-standing volatile object when the semantics specify a
single access.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.l earn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #10

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

Similar topics

1
1829
by: VNG | last post by:
I have an ANSI C program that was compiled under Windows MSVC++ 6.0 (SP6) and under Linux gnu, and ran under P3, P4 and AMD. It runs fine on P3 and AMD under both Windows and Linux, but under P4 it has problems. Under Windows 3GHz P4 runs twice slower than 800MHz P3... and under Linux not only that it runs slower (while AMD is 40 times faster), but it also produces wrong numerical results... Any suggestion what can be the problem?
100
6928
by: Roose | last post by:
Just to make a tangential point here, in case anyone new to C doesn't understand what all these flame wars are about. Shorthand title: "My boss would fire me if I wrote 100% ANSI C code" We are discussing whether this newsgroup should focus on 100% ANSI C or simply topics related to the C language in the real world. There is a C standard which is defined by an international committee. People who write compilers refer to this in...
8
2631
by: Tim Rentsch | last post by:
Here's another question related to 'volatile'. Consider the following: int x; void foo(){ int y; y = (volatile int) x;
4
3145
by: TGOS | last post by:
I was thinking about it for a while, a mutex written in C and without disabling any interrupts. Is it possible? typdef struct mutex { unsigned int owner1; unsigend int owner2; } *mutex; void mutex_init(mutex *m) {
15
1977
by: Marc Thrun | last post by:
Hello, I've got a few questions: 1) Given the two structs struct A { int x; }; and
1
1621
by: Eric | last post by:
I have some questions about the volatile keyword... 1) If I use the volatile keyword with a reference type such as a class like so: public volatile UserTotals totals = new UserTotals(); Are the fields of the class also protected? Or is it just the 4-8 byte reference to the object that is protected?
11
1597
by: Sensei | last post by:
Hi again! I have still curiosity about the reason of some C constructs/keywords... The first is about static functions. What was the reason of restricting a function to be visible just in a specific source file? Wasn't it sufficient not to be given a prototype (for visibility)? What about register and volatile variables? Was at that time a compiler not smart enough to optimize with in-register variables? And why would
5
1931
by: George2 | last post by:
Hello everyone, The following code, operator const Outer::Inner * volatile & (); 1.
16
1818
by: Ark Khasin | last post by:
I have a memory-mapped peripheral with a mapping like, say, struct T {uint8_t read, write, status, forkicks;}; If I slap a volatile on an object of type struct T, does it guarantee that all accesses to the members are byte-wide, or is the compiler free to read or read-modify-write in any data width it chooses? Is slapping a volatile on each member of the struct definition any different? better? worse?
0
8266
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8705
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8638
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
8365
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8505
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7196
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6125
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4092
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
1511
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.