Monday, July 23, 2018

Digest for comp.lang.c++@googlegroups.com - 25 updates in 11 topics

Lynn McGuire <lynnmcguire5@gmail.com>: Jul 17 02:36PM -0500

On 7/17/2018 12:47 PM, Richard wrote:
 
> ...but back to the topic of the article. This is like the 40th time
> that someone has complained about C++ and introduced a new language to
> "solve" the problems that C++ has.
 
Shoot, it could the 400th time.
 
Lynn
Thiago Adams <thiago.adams@gmail.com>: Jul 23 07:41AM -0700

On Friday, July 20, 2018 at 5:51:57 PM UTC-3, Richard wrote:
...
> However, I find myself working in larger problem spaces now and C
> doesn't scale well to larger code bases because of its limited ability
> to express abstractions directly in code.
 
I would like to understand better what you want to say.
More abstract code scale better? How? Maybe because you can
do the same think in less lines of code?
 
I believe C can scale well. (Maybe SOs are a good sample?)
 
One case where C would not scale well is let's say you
build a container (like map something like that) and
then you have to duplicate the code and create other
containers because you don't have templates.
Then at some point you realize that the
implementation should be a little bit different, and then is
hard to change all the implementations (duplicate code) you have.
The C alternatives to solve this problem are not so easy as
well.
 
But I would like to hear other opinions about this.
legalize+jeeves@mail.xmission.com (Richard): Jul 23 03:40PM

[Please do not mail me a copy of your followup]
 
Thiago Adams <thiago.adams@gmail.com> spake the secret code
 
>I would like to understand better what you want to say.
>More abstract code scale better? How? Maybe because you can
>do the same think in less lines of code?
 
C only has two facilities for abstraction: the struct and the function.
 
While it is possible to build abstract data types on top of these two
things (e.g. every "handle" based API in existence), the language
doesn't really help you out. You can't do things like use 3D vectors
or 3D points naturally with transformation matrices. (I often work
in the 3D graphics problem domain.) Everything has to be written in
terms of function calls instead of the natural notation of the problem
space. This is one of the problem domains that is very "mathematical"
in nature and overloading the arithemetic operators makes very good
sense.
 
Even outside of a mathematically oriented problem domain, I can't
express object-oriented relationships between concepts directly in C.
I have to invent my own virtual function mechanism using function
pointers and the whole thing is very fragile. It can be done, but it
requires significant programmer discipline in order to avoid bugs due
to the manual nature of the mechanisms that you must use in C because
the language doesn't support the construct directly. A good example
is the abstractions in the X Window System server -- everything is
done in an object-oriented way *by hand* because the server was
written in C in order to obtain the most portability at the time.
(The Xserver predates widespread adoption of C++.)
 
>I believe C can scale well. (Maybe SOs are a good sample?)
 
It can be done, but the language doesn't support sufficient
abstraction mechanisms in order for the scaling to be done well.
 
>build a container (like map something like that) and
>then you have to duplicate the code and create other
>containers because you don't have templates.
 
Yes, this is another example where C has insufficient abstraction
mechanisms to avoid code duplication, but this is not the kind of
scaling I'm talking about.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Jul 23 03:44PM

[Please do not mail me a copy of your followup]
 
Cholo Lennon <chololennon@hotmail.com> spake the secret code
 
>My problem with CLion (and Eclipse CDT) is the slow code indexing, it's
>really slow. Qt Creator and Visual Studio don't have this problem. I use
>CMake in all cases.
 
They continue to improve it over time. However the consequence of the
extensive indexing is that the refactoring is much more accurate than
other tools. ReSharper for C++ and CLion routinely get the best
scores on my refactoring test suite[1]. I don't know how much of the
slowness is due to the implementation being in Java/C#. It's a "road
not taken" hypothesis and the only way to get a fair measurement would
be to reimplement the entire system in C++ and spend a lot of time
tuning the C++. I guarantee you that they spend time tuning the IDE
and improve it over time as I have witnessed many improvements over
time. I used CLion on the LLVM/clang codebase, which is *huge*. This
was a couple years ago, so I haven't tested more recent builds but I
expect them to be much faster.
 
[1] <https://github.com/LegalizeAdulthood/refactor-test-suite>
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
legalize+jeeves@mail.xmission.com (Richard): Jul 23 03:45PM

[Please do not mail me a copy of your followup]
 
Cholo Lennon <chololennon@hotmail.com> spake the secret code
>with big Java projects. What is more, I don't know why CLion and Eclipse
>CDT perform a full reindex every time I open a project, that's
>unnecessary IMO :-O
 
File bugs. JetBrains is much more responsive to my bug reports than
other software vendors.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
jacobnavia <jacob@jacob.remcomp.fr>: Jul 23 08:41PM +0200

Le 23/07/2018 à 17:40, Richard a écrit :
> build a container (like map something like that) and
> then you have to duplicate the code and create other
> containers because you don't have templates.
 
Look at the C containers library. The code is available for free at:
 
https://github.com/shiva/ccl
 
I use simply a set of macros to define a container for any type <T>
 
jacob navia
Thiago Adams <thiago.adams@gmail.com>: Jul 23 12:56PM -0700

On Monday, July 23, 2018 at 3:41:41 PM UTC-3, jacobnavia wrote:
 
> https://github.com/shiva/ccl
 
> I use simply a set of macros to define a container for any type <T>
 
> jacob navia
 
I already sent my comments on comp lang c for this lib
some time ago.
jacobnavia <jacob@jacob.remcomp.fr>: Jul 23 10:14PM +0200

Le 23/07/2018 à 21:56, Thiago Adams a écrit :
 
>> jacob navia
 
> I already sent my comments on comp lang c for this lib
> some time ago.
 
I do not remember all threads you started, sorry.
 
I told you that "some time ago"...
 
:-)
 
In any case, for the people that do not read that threads, care to comment?
legalize+jeeves@mail.xmission.com (Richard): Jul 23 08:38PM

[Please do not mail me a copy of your followup]
 
jacob@jacob.remcomp.fr spake the secret code
>> build a container (like map something like that) and
>> then you have to duplicate the code and create other
>> containers because you don't have templates.
 
Nit: I didn't write the above.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Vir Campestris <vir.campestris@invalid.invalid>: Jul 16 09:46PM +0100

> Given C doesn't have exceptions but only explicit returns then remembering
> to call free on a local pointer is hardly onorous.
 
Suppose we have a complex function, that allocates several things,
performs checks on the way, and bails out when it doesn't like a result.
 
Then suppose you want to re-order the checks. You then have to edit the
cleanup before each return:
 
bool dosomething
{
// block 1
type * a = new type;
some checks
if error { free a ; return false; }
 
// block 2
type b = new type;
some more checks
if error { free a ; free b ;return false; }
 
some more code
free a; free b;
return true
}
Now swap block 1 and block 2 around. Don't forget to edit the free
statements.
 
The only way I've seen that maintains your sanity is the Linux kernel
way - use goto as an exception.
 
bool dosomething
{
type * a = null;
type * b = null;
bool ret;
 
a = new type;
some checks
if error { ret = false; goto error }
 
b = new type;
some more checks
if error { ret = false; goto error }
 
some more code
ret = true;
error:

free a; free b;
return ret;
}
 
Compare C++
 
bool dosomething
{
unique_ptr<type> a = std::make_unique<type>();
some checks
if error return false;
 
// block 2
unique_ptr<type> b = std::make_unique<type>();
some more checks
if error return false;
 
some more code
return true
}
 
Andy
Vir Campestris <vir.campestris@invalid.invalid>: Jul 16 09:49PM +0100

On 16/07/2018 18:23, Paavo Helde wrote:
> That's true. Compilation time is my main complaint about C++.
 
We use a thing called Icecream
 
https://github.com/icecc/icecream
 
It spreads the compile load around the office. I normally run my makes
with -J128 - any higher than that and idon't gain, as it takes too long
to send the work out. We have over 300 cores in the pool in our little
branch office.
 
Andy
bitrex <user@example.net>: Jul 19 01:42PM -0400


>> So removing something that has no cost is a sound engineering decision?
 
> There's no such thing as no cost in creating and destructing objects no matter
> how slimline they may be and smart pointers are objects.
 
If a unique_ptr object has no persistent state other than the wrapped
pointer itself, which is the same persistent state the equivalent
smart-pointer-free code would have, and the rest of the object's
behavior is simply no different than the effect of writing "new" and
"delete" at the appropriate times (or malloc/free in C) then that is
precisely what the compiler will do and that's what the compiler will
generate.
 
What sense would it make to do anything else?
bitrex <user@example.net>: Jul 19 01:46PM -0400


>> So removing something that has no cost is a sound engineering decision?
 
> There's no such thing as no cost in creating and destructing objects no matter
> how slimline they may be and smart pointers are objects.
 
You're laboring under the assumption that every time you write Object
object; in your code the compiler is actually producing code to execute
constructors (that may do nothing at all), jump into destructors (that
may do nothing at all), making stack allocations, assigning-immediate
class member variables, running all around doing this and that. Every time.
 
That isn't how modern optimizing compilers work.
Bart <bc@freeuk.com>: Jul 16 10:40PM +0100

On 16/07/2018 22:20, Stefan Ram wrote:
> { println( java.lang.Character::isJavaIdentifierStart );
> println( Main::identbody ); }}
 
> transcript
 
It's a mystery how you get from the above to the following:
 
> $ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
> $0123456789ABCDEFGHIJKLMNOPQRSTUVWXY_abcdefghijklmnopqrstuvwxyz
 
This is why expressiveness in the code is important - within reason
otherwise too much will become cryptic. Even with the C code you can see
where and how the 'A' to 'Z' range was defined.
 
(The default printing I use only shows numbers, but will work out the
ranges:
 
[36,65..90,95,97..122]
[36,48..57,65..89,95,97..122]
 
This is handy for rather larger sets:
 
println [1..1000'000'000]
 
Output:
 
[1..1000000000]
 
which would otherwise take too long to print.)
 
--
bart
Bo Persson <bop@gmb.dk>: Jul 18 12:26PM +0200

On 2018-07-18 11:23, Ralf Fassel wrote:
 
> IMHO in the above the DTOR of X should always get called regardless of
> F() throwing or not.
 
> R'
 
No, main is not special (in this regard). The difference is having a
try-catch, or not.
 
Implementations are allowed to first go looking for the catch clause,
and only then run the destructors for the stack objects. Or it could
unwind one stack frame at a time while searching for the catch-clause.
 
Makes a difference if the is NO try-catch in the current line of
execution, so that the thrown exception leaves main. Could mean that the
program is just terminated without executing any destructors.
 
 
Bo Persson
Paavo Helde <myfirstname@osa.pri.ee>: Jul 18 06:58PM +0300

On 18.07.2018 16:04, Thiago Adams wrote:
 
> It must have some overhead in size because it has to build
> the "landing pads" and tables state->landing pads.
 
Yes, it trades some disk space for speed, but the size of executables
does not interest most people nowadays (except some nutwits in this group).
 
> Also it has to change some state (let's say change one pointer,
> I don't known) while the code is completing ctors.
 
In principle the state of the IP (instruction pointer) could be enough,
don't know how it is actually done.
 
> stack unwinding, but the document [1] says it uses
> compression. The compression means that the states
> table can be large.
 
I believe they deal with relative jump offsets which are typically small
numbers, so they are compressing away the high-order zero bytes. Can
probably give something like 8x compression. Decompressing is a bit
tedious but as this happens on the exceptional code path only it does
not matter.
scott@slp53.sl.home (Scott Lurndal): Jul 18 05:06PM

>> does not interest most people nowadays (except some nutwits in this group).
 
>Caring about the size of your executables pays off in
>terms of runtimes and build times.
 
Nonsense.
 
> This talk by Mark
>Zeren at Cppnow is a little vindication for the nutwits.
 
Who is Mark Zeren, and why should I care?
 
 
>https://duckduckgo.com/?q=cppnow+matters&t=h_&ia=videos&iax=videos&iai=vGV5u1nxqd8
 
Sorry, can't do videos and don't do duckduckgo. Post the actual link
to words instead of the search terms.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jul 19 10:36PM +0100

On 19/07/2018 22:12, Thiago Adams wrote:
> that will always be used together because they depend on
> each other to build and they can be reused in other
> projects just coping the folder.
 
Is this a deliberate troll? I sincerely hope so as the alternative is too
depressing to think about.
 
/Flibble
 
--
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
ram@zedat.fu-berlin.de (Stefan Ram): Jul 16 08:53PM

>But to go back to an earlier point, this sort of stuff really belongs in
>a higher level language (higher level than C++)
 
main.pl6
 
my $identstarter =( 'A' .. 'Z', 'a' .. 'z', '_', '$' ).Set;
my $identbody =( $identstarter ∪ ( '0' .. '9' ))∖( 'Z' );
say $identstarter;
say $identbody;
 
transcript
 
set($ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ a b c d e f g h i j k l m n o p q r s t u v w x y z)
set($ 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y _ a b c d e f g h i j k l m n o p q r s t u v w x y z)
 
ASCII version
 
my $identstarter =( 'A' .. 'Z', 'a' .. 'z', '_', '$' ).Set;
my $identbody =( $identstarter (|) ( '0' .. '9' ) ) (-) ( 'Z' );
say $identstarter;
say $identbody;
% <Persent@gmail.com>: Jul 18 06:23AM -0700

On 2018-07-17 3:32 AM, Storage Unit wrote:
> those paths contain non-ASCII characters.
 
>> Microsoft has been reliant on hard-coded paths since before Windows,
>> and Windows 10 is no different.
 
then why aren't you using 10
gof@somewhere.invalid (Adam Wysocki): Jul 19 12:25PM


> Somebody posted on comp.lang.asm.x86 an algorithm for fizz buzz.
 
There are many language tricks and hacks to make the solution interesting,
but I prefer solutions that are readable and simple enough to do the task.
 
The cleanest (definitely not the shortest) solution I could come up with
(in C++):
 
#v+
#include <boost/format.hpp>
#include <iostream>
 
static const unsigned MIN_NUMBER = 1;
static const unsigned MAX_NUMBER = 100;
 
/**
* \brief Check if value is divisible by another value
*
* \retval true Dividend is divisible by divisor
* \retval false Value is not divisible by divisor
*/
 
static inline bool isDivisible(unsigned dividend, unsigned divisor)
{
return !(dividend % divisor);
}
 
/**
* \brief Make word according to FizzBuzz rules
*
* Returns word according to FizzBuzz rules, that is:
*
* - if value is divisible by 3 and not by 5, returns "Fizz"
* - if value is divisible by 5 and not by 3, returns "Buzz"
* - if value is divisible both by 3 and 5, returns "Fizz Buzz"
* - as the last resort, returns string containing the value
*
* \param number Number to check
* \return String according to FizzBuzz rules
*/
 
static std::string makeWord(unsigned number)
{
std::string word;
 
if (isDivisible(number, 3))
word += "Fizz";
 
if (isDivisible(number, 5))
{
if (!word.empty())
word += " ";
 
word += "Buzz";
}
 
if (word.empty())
word = boost::str(boost::format("%u") % number);
 
return word;
}
 
int main()
{
for (unsigned i(MIN_NUMBER); i <= MAX_NUMBER; ++i)
{
const std::string suffix(i != MAX_NUMBER ? ", " : "\n");
std::cout << makeWord(i) << suffix;
}
 
return 0;
}
#v-
 
--
[ Adam Wysocki :: Warsaw, Poland ]
[ Email: a@b a=grp b=chmurka.net ]
[ Web: http://www.chmurka.net/ ]
Bo Persson <bop@gmb.dk>: Jul 19 08:19PM +0200

On 2018-07-19 16:06, Thiago Adams wrote:
> p2 = std::move(p1);
 
> in this case, the compiler would be allowed to remove
> the destructor call of the p1.
 
You know, perhaps it already does that?
 
Here is the result on MSVC 2017:
 
 
#include <memory>
int main()
{
00007FF7893D1000 sub rsp,28h
std::unique_ptr<int> p1 = std::make_unique<int>();
00007FF7893D1004 mov ecx,4
00007FF7893D1009 call operator new (07FF7893D1024h)
00007FF7893D100E xor ecx,ecx
00007FF7893D1010 mov dword ptr [rax],ecx
std::unique_ptr<int> p2;
p2 = std::move(p1);
 
}
00007FF7893D1012 lea edx,[rcx+4]
00007FF7893D1015 mov rcx,rax
00007FF7893D1018 call operator delete (07FF7893D1060h)
00007FF7893D101D xor eax,eax
00007FF7893D101F add rsp,28h
00007FF7893D1023 ret
 
 
What destructor call do you want to remove?
 
 
Bo Persson
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 20 12:23AM +0200

This can cause an exception or possibly just a crash or UB, in Windows:
 
std::locale{ setlocale( LC_ALL, nullptr ) }
 
Full example program:
 
 
-------------------------------------------------------------------------
#include <iostream>
#include <locale>
#include <locale.h>
#include <stdexcept>
#include <stdlib.h>
 
auto main()
-> int
{
setlocale( LC_ALL, "" ); // Default national locale (UTF-8 in *nix)
setlocale( LC_NUMERIC, "C" ); // Periods as fraction
separators, please.
 
std::cout << "C level locale = \"" << setlocale( LC_ALL, nullptr )
<< "\"\n";
 
try
{
const auto& loc = std::locale{ setlocale( LC_ALL, nullptr ) };
std::cout << "C++ level locale = " << loc.name() << "\n";
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << "\n";
}
catch( ... )
{
std::cerr << "!!! non-standard exception\n";
}
return EXIT_FAILURE;
}
-------------------------------------------------------------------------
 
 
Results with respectively Visual C++ and MinGW g++, in that order:
 
 
-------------------------------------------------------------------------
[P:\temp]
> cl locale-sabotage.cpp /Feb
locale-sabotage.cpp
 
[P:\temp]
> b
C level locale = "LC_COLLATE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_CTYPE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_MONETARY=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_NUMERIC=C;LC_TIME=Norwegian Bokmål_Svalbard and Jan
Mayen.1252"
C++ level locale = LC_COLLATE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_CTYPE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_MONETARY=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_NUMERIC=C;LC_TIME=Norwegian Bokmål_Svalbard and Jan Mayen.1252
 
[P:\temp]
> g++ locale-sabotage.cpp
 
[P:\temp]
> a
C level locale = "LC_COLLATE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_CTYPE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_MONETARY=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_NUMERIC=C;LC_TIME=Norwegian Bokmål_Svalbard and Jan
Mayen.1252"
!locale::facet::_S_create_c_locale name not valid
-------------------------------------------------------------------------
 
 
This is in Windows 10. I seem to remember that locale names were like
"no_NB.1252", and not the long descriptive text above. Has something
changed?
 
Because I also remember g++'s C++ level locale handling to be missing or
screwed up, so that /could/ be the problem?
 
 
Cheers!,
 
- Alf
Tim Rentsch <txr@alumni.caltech.edu>: Jul 18 10:55AM -0700

>> the requirements.
 
> Maybe we should say in many cases, the TDD tests are the only form
> of requirements...
 
This statement confuses several significantly distinct notions,
which in turn confuses the issue.
 
The /requirements/ of a desired program are all those things
that need to be true in order for the program to be useful in
accomplishing its intended purpose. These things may be called
the actual or true requirements.
 
A /statement of requirements/ is what results from an effort to
capture those things in a verbal (usually written) form. A key
difference is that we know what is included in a statement of
requirements, but often don't know what is included in the
actual requirements, because customers often aren't sure or
don't understand what is really needed.
 
An effort to establish that a statement of requirements matches
the actual requirements is called validation (in particular, in
the software world it is called software validation). An effort
to establish that a program's behavior matches its statement of
requirements is called software verification. Informally, the
phrases "build the right thing" and "build the thing right" are
sometimes used for validation and verification, respectively.
 
A set of tests written (under any methodology) to help establish
program behavior, under certain circumstances, generally falls
into the category of verification. Some of those tests -- in
particular, those that check end-to-end externally visible
program behavior -- might correspond to parts of a statement of
requirements. In contrast, internal tests might be useful in
helping verify a program's behavior, but they never belong in a
statement of requirements, because the customer doesn't care
about how a program operates internally (or if they do, it means
those predicates are not really internal conditions).
 
Of course, a customer might agree, whether explicitly or not,
that passing some set of tests (perhaps in addition to some
other criteria) means the program is satisfactory as far as they
are concerned. Any set of tests might be part of an acceptance
measure. But being part of an acceptance measure doesn't mean a
specific tested condition belongs in a statement of requirements
necessarily. Moreover, even if a particular condition is agreed
to be part of a statement of requirements, that doesn't change
the actual requirements, which are not affected (even if not
always knowable) by what the statement of requirements says.
Bottom line, if after delivery a program never gets used to
accomplish what the customer wanted to accomplish with it, the
program has not met its requirements. It may be that it has met
its contractual obligations, but that doesn't guarantee that it
has met its actual requirements.
Paavo Helde <myfirstname@osa.pri.ee>: Jul 18 08:49PM +0300

On 18.07.2018 19:57, Daniel wrote:
 
> to return 10 or 20 depending on the size of the integer, or not compile if
> the integer type is not 32 or 64 bits.
 
> I'm having some difficulty solving this with SFINAE. Any suggestions?
 
Something like this?
 
#include <iostream>
 
class A
{
int32_t value1_;
int64_t value2_;
private:
template<int sz> struct traits { using type = void; };
template<> struct traits<4> { using type = int32_t; };
template<> struct traits<8> { using type = int64_t; };
 
template<int sz> typename traits<sz>::type Get() const;
template<> traits<4>::type Get<4>() const { return value1_; }
template<> traits<8>::type Get<8>() const { return value2_; }
 
public:
A() : value1_(10), value2_(20) {}
 
template<typename T>
explicit operator T() const
{
return Get<sizeof(T)>();
}
};
 
int main()
{
A a;
 
std::cout << (int32_t)a << ", " << (int64_t)a << std::endl;
}
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: