Tuesday, January 21, 2014

comp.lang.c - 26 new messages in 4 topics - digest

comp.lang.c
http://groups.google.com/group/comp.lang.c?hl=en

comp.lang.c@googlegroups.com

Today's topics:

* Non-constant constant strings - 15 messages, 5 authors
http://groups.google.com/group/comp.lang.c/t/5fe3752eb851a432?hl=en
* The Beauties of Islam - 2 messages, 2 authors
http://groups.google.com/group/comp.lang.c/t/3dd0812854727916?hl=en
* Crazy but valid C... - 3 messages, 3 authors
http://groups.google.com/group/comp.lang.c/t/184fe3b933cf3175?hl=en
* Black magic, or insanity? - 6 messages, 4 authors
http://groups.google.com/group/comp.lang.c/t/ef5c82b8c8bd554c?hl=en

==============================================================================
TOPIC: Non-constant constant strings
http://groups.google.com/group/comp.lang.c/t/5fe3752eb851a432?hl=en
==============================================================================

== 1 of 15 ==
Date: Mon, Jan 20 2014 2:37 pm
From: Seebs


On 2014-01-20, Rick C. Hodgin <rick.c.hodgin@gmail.com> wrote:
> On Monday, January 20, 2014 3:31:34 PM UTC-5, Eric Sosman wrote:
>> But that was long ago: The uniqueness guarantee (and any
>> accompanying mutability) was rescinded by the original ANSI C
>> Standard way back in 1989.

> And I bet you could hear the thuds on the floor as many developers
> screamed "WHAT!" and then passed out.

I don't think so. Back in the late 80s, when I was just starting to
learn C, I was aware that if you had two string literals, and one was
the same characters as the tail end of the other, the compiler might
use the same storage for both. It's really easy to obtain a modifiable
string if I want one, so I don't expect literals to be modifiable, or
indeed, even to occur in code or storage anywhere if they don't really
have to.

-s
--
Copyright 2013, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
Autism Speaks does not speak for me. http://autisticadvocacy.org/
I am not speaking for my employer, although they do rent some of my opinions.




== 2 of 15 ==
Date: Mon, Jan 20 2014 3:14 pm
From: Seebs


On 2014-01-20, Rick C. Hodgin <rick.c.hodgin@gmail.com> wrote:
> On Monday, January 20, 2014 2:10:40 PM UTC-5, glen herrmannsfeldt wrote:
>> Oh, also, one of my favorite C features (Java also has), you
>> can have the extra comma on the last line. Convenient for program
>> generated text, though most likely in the standard as it allows
>> for easy preprocessor conditionals.

> See, and I think that such an "allowance" is patently absurd and should not be a part of any language. :-)

Why? It's really convenient as a way to eliminate a gratuitous special
case.

-s
--
Copyright 2013, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
Autism Speaks does not speak for me. http://autisticadvocacy.org/
I am not speaking for my employer, although they do rent some of my opinions.




== 3 of 15 ==
Date: Tues, Jan 21 2014 1:39 am
From: "BartC"




"Keith Thompson" <kst-u@mib.org> wrote in message
news:lneh42z2b1.fsf@nuthaus.mib.org...
> "BartC" <bc@freeuk.com> writes:

>> So if the text in the file was:
>>
>> one
>> two
>> three
>>
>> then including that file would be equivalent to:
>>
>> "one\ntwo\nthree\n"
>>
>> in the source code. (Obviously in C it would need to be allowed inside an
>> expression.)
>
> #include directives are already allowed inside expressions, though they
> still don't have a way to convert the input file content to a string
> literal.

Sure, I forgot you can have a term of an expression on its own line and so
make it possible to insert a # directive.

> For example:
>
> $ cat hello.inc
> "Hello, world"
> $ cat hello.c
> #include <stdio.h>
> int main(void) {
> puts(
> #include "hello.inc"
> );
> }
> $ gcc hello.c -o hello && ./hello
> Hello, world
> $

It seems a fine distinction, but not requiring the text in the included file
to be quoted (ie. written out as one or a series of valid C string constants
complete with escape codes) means text from any source can be used, which
can be created/edited by anyone with any text editor. That was the advantage
that struck me.

Although such an include wouldn't work recursively. This means a C source
file can include a string constant containing the entire C source file
itself!

(I've just spent ten minutes implementing such a feature, to show it's
workable. However it possible, even with C, to read a file into a string
using a single function call (in C, you have write the function first). So
it's mainly useful where large, statically allocated string constants are
needed. As in the OP's requirement perhaps.)

--
Bartc





== 4 of 15 ==
Date: Tues, Jan 21 2014 3:51 am
From: "Rick C. Hodgin"


On Monday, January 20, 2014 4:29:28 PM UTC-5, Eric Sosman wrote:
> >> C string literals are intended to be *constant*.
> > They are most often intended to be constant, but not always. There are
> > many cases where developers allocate something with an initial value, but
> > then alter it at runtime.
> > char defaultOption[] = "4";
> > In this case, the default option is 4 until the user changes it. It's a
> > constant bit of text, but is not constant. :-)
>
> No, not at all. `defaultOption' (either version) is not a
> constant, but a variable. It has an initial value, that's all.
> You can change the variable's value with one of

That was my point. In my char* list[] = { ... } case, I want initial values, but not constants. I type them in the same way, but they have different meanings.

> In none of these cases is there any need to change the value
> of a constant, nor any reason to want to do so.

I don't want to change the value of a constant. By definition one should not be able to do that. :-)

What I want is a way to change the value of my variable, the one defined and stored as a literal string in source code, one that I desire to be a variable, yet the one being interpreted by the compiler as a constant instead of a variable with no apparent override available to direct it where I would like it to go even though those members in attendance were content to allow such an ability through common extensions (nearly all of which were later dropped it seems).

Best regards,
Rick C. Hodgin




== 5 of 15 ==
Date: Tues, Jan 21 2014 3:57 am
From: "Rick C. Hodgin"


On Monday, January 20, 2014 4:32:04 PM UTC-5, Eric Sosman wrote:
> On 1/20/2014 3:42 PM, Rick C. Hodgin wrote:
> >> But that was long ago: The uniqueness guarantee (and any
> >> accompanying mutability) was rescinded by the original ANSI C
> >> Standard way back in 1989.
>
> > And I bet you could hear the thuds on the floor as many developers
> > screamed "WHAT!" and then passed out.
> Did you miss the part about "Those members ... were content?"

Not at all. I presumed "those members" involved in the ANSI authorizing were a small number, power-seeking representatives of the entire C language developer base of us "little people," while the much larger group (developers who were coding in C in general) contained many developers, and it was many of them who screamed "WHAT!" and then passed out.

> At that time I was a developer with not quite twenty years'
> worth of C experience, and I neither screamed nor thudded. YMMV.

MMDV.

> >> Quoth the Rationale:
> >> "String literals are not required to be modifiable. This
> >> specification allows implementations to share copies of
> >> strings with identical text, to place string literals in
> >> [...] Those members of the C89 Committee who insisted that
> >> string literals should be modifiable were content to have
> >> this practice designated a common extension [...]"
> > The word "common" being used very loosely there. LOL! :-)
> See Appendix J.

Appendix J of what?

Best regards,
Rick C. Hodgin




== 6 of 15 ==
Date: Tues, Jan 21 2014 4:47 am
From: "Rick C. Hodgin"


> > char defaultOption = "4";
> Did you mean "char *defaultOption" or "char defaultOption[]" rather than
> "char defaultOptions", or did you mean '4' rather than "4"?

I meant char defaultOption[] = "4";

> > I would like to be able to specify that with a const prefix, as in this
> > type of syntax:
> >
> > char* list[] =
> > {
> > "foo1",
> > const "foo2",
> > "foo3"
> > }
> >
> > In this case, I do not want the second element to be changed, but the
> > first and third... they can change.
>
> If I were to suggest a new language feature to support that, I'd want an
> explicit marker for a string that I *do* want to be able to change.

I realize that. My view, of course, differs. :-)

> In your proposed C-like language, what would this snippet print?
> for (int i = 0; i < 2; i ++) {
> char *s = "hello";
> if (i == 0) {
> s[0] = 'H';
> }
> puts(s);
> }

Interesting.

FWIW, I don't believe in defining variables in this way in C. I believe an
initialization block should exist so it is being done explicitly, both for
documentation purposes, and clarity in reading the source code (it's very
easy to miss a nested declaration when a group of variables is created of
a similar type.

In my proposed language, it would print "Hello" both times because the
char* s definition would've been pulled out of the loop and defined as a
function variable. If the user wanted independent copies each iteration
he would have to create them and manage them himself, which I think
documents the condition of the code more explicitly, making it far
easier for someone to see what's going on rather than inferring from
language peculiarities which may not be consistent across compiler
versions (they probably are in this case, but I've seen other similar
conditions which vary between Visual C++ and GCC).

I would rewrite your function to look like this (because I believe it
should behave this way):

void foo(void)
{
int i;
char* s; // Note I use the D language syntax of keeping the pointer
// symbol near the type, rather than the variable.

// Initialization
s = "hello";

// Code
for (i = 0; i < 2; i ++)
{
// I introduce predicates, which logically operate more like this:
if (i == 0) s[0] = 'H';

// Displays "Hello" both times
puts(s);
}
}

To mimic your functionality, I would code this way:

const char gcHello[] = "hello";

void foo(void)
{
int i;
char s[7];


// Initialization (a compiler switch would make this automatic)
memset(s, 0, sizeof(s)); // Here it's done manually

// Code
for (i = 0; i < 2; i ++)
{
// Iterative re/initialization
memcpy(s, gcHello, -2); // My memcpy would support a p3 of -1 to
// automatically perform strlen() on p3,
// and -2 would be strlen()+1.

// First pass conversion only
if (i == 0) s[0] = 'H';

// Displays "Hello" then "hello"
puts(s);
}
}

> In C as it's currently defined, the string literal "hello" corresponds
> to an anonymous array object with static storage duration; attempting to
> modify it has undefined behavior. As I understand it, you want to
> remove the second part of that. The above code has one occurrence of a
> string literal, but it's being used in the initializer for two distinct
> objects. On the second iteration, does s point to a string with
> contents "hello" or "Hello"?
>
> Either interpretation is problematic.

Exactly. So, you don't code that way. :-)

You make everything a function-level variable and it's done. You make
all code items read/write unless they are explicitly prefixed with a
const or have some macro wrapper like _rw("foo") or _fo("foo") to
explicitly name them.

> >> The fact that such checks are not required is for backwards
> >> compability for code written before the "const" keyword was added to the
> >> language; even if not for that, C tends to make such things undefined
> >> behavior rather than requiring run-time diagnostics.
>
> > Well ... there's logic there. It makes sense. I think it's time for a
> > switchover though. We're getting into multi-processor programming, multiple
> > threads. Where we are in 2010s and later is not where we were in 1980s.
>
> I fail to see how this argues for modifiable string literals.

Not just string literals, but a separation of the "before" and the "after."
Programming today is, by default, targeted at multiple CPUs. There are
functions which run top-down, but on the whole we are creating
multi-threaded congruent code execution engines running on commensurate
hardware. The time for a new language syntax is at hand.

I propose new extensions to C in general:

in (thread_name) {
// Do some code in this thread
} and in (other_thread_name) {
// Do some code in this thread
}

And a new tjoin keyword to join threads before continuing:
tjoin this, thread_name, other_thread_name


flow name {
flowto name;

always before {
}

always after {
}

function name {
}

subflow name {
}

error name {
}

} // end flow

And I propose the new concept of a cask, a "pill" that is inserted anywhere
in code to do whatever I like, along with explicit cask definitions that do
certain things based upon called functions which can convey branch logic
upon returning.

Casks look like this (|sample|) and they would operate like this:

Traditional code:
if (some_test(1, 2, 3)) {
// Do something
}

In this case:
push 3
push 2
push 1
call some_test
compare result to 0
if not equal, enter the block

The ability to insert a cask does not alter program logic:
if ( (|cask1|) some_test( (|cask2|) 1, 2, (|cask3|) 3) {
// Do something
}

In this case:
push 3
call cask3
push 2
push 1
call cask2
call some_test
call cask1
compare result from some_test to 0
if not equal, enter the block

The casks are called functions which can be inserted at any point without
otherwise affecting program logic (hence their new shape). I wrote it with
spaces above to make it more clear, but it could be coded like this:
if ((|cask1|)some_test((|cask2|)1, 2, (|cask3|)3)

And I have other ideas. You can read about them on this page. This page
specifically relates to extensions to Visual FoxPro, but my intention is
my RDC (Rapid Development Compiler) which is C-like, but relaxes a lot of
stringent errors in C reporting them only as warnings, such as pointer-to-
pointer conversions, allowing for them to be perfectly valid, and many
other changes as well.

http://www.visual-freepro.org/wiki/index.php/VXB++

Each of these add-ons should be language-level first class citizens which are known to the language and allow for modern CPU architectures with various new data types and volatile extensions which operate around explicitly semaphored access at the language level, along with certain optimization constraints and allowances (as per the developer's dictates, even of the kind which can override "safety" on variable use -- meaning that a particular case could violate atomicity and the compiler knows it, but the compiler is a tool and should allow what the developer dictates because the developer is a person and has real authority).

My opinion. My goals. :-)

> > I realize C operates this way and it's fine. I think the future standard
> > should be that everything is in read-write memory except those things
> > explicitly prefixed with const, or a new _c("text") macro which identifies
> > that data explicitly as a constant.
>
> As a language design issue, I *strongly* disagree with this.
> Personally, I like the idea of making everything read-only unless you
> explicitly say you want to be able to modify it. (Obviously C isn't
> defined this way; equally obviously, this is merely my own opinion.)

I look at computers as being exactly that: computers. They compute. Their
purpose is to take input, process it, and store output. That storage portion
automatically means write abilities, and the input combination means
read-write as it is more common to operate through a chain of processing
where a recently computed and written value is then quickly used thereafter
as input to a follow-on computation.

Everything should be read-write unless explicitly stated as read-only. My
opinion, and my position in any languages I author. :-)

> BTW, your _c("text") macro would still have to be defined somehow;
> a new kind of string literal would probably make more sense.

I think string literals should all use double-quotes, but it should be a
different double-quote character from ASCII-34, and one for left and one
for right, so they can be nested and mate up as parenthesis. I also
believe variables should be allowed to have spaces, but it should be a
different space character than ASCII-32. In my implementation of RDC,
Visual FreePro, my virtual machine, I will introduce ASCII characters which
explicitly serve these purposes at the developer level, allowing for double-
quoted characters to be used as raw input without first escaping them. I
will also allow other explicit ASCII characters between the new double quote
characters in their raw single-symbol form without escaping.

We're past the days of limited abilities. We have GUIs now that can draw any
icon, any character ... it's time to grow up. :-)

There are a lot of things which were done badly in the early days of
programming. Many rigid constraints which make difficult-to-read-and-understand source code. The concept of a header, for example, is
no longer required when 16GB of memory is $700 or less and will only
get cheaper over time.

It's time to rethink what's been thought, and undo the damage that's been
done, to look to the current and future needs of multi-core, parallel-thread,
object-oriented design, yet with all of it having an explicit base in the raw
compute needs of the machine. C is ideal for that. C++ takes the idea of
object orientation too far.

In C++, foo->function(). The better syntax is foo.function() (for both
pointers to variables, and declared variables), and such is a mild
extension of the existing struct:

struct SFoo
{
void function(void);

int member_variable;
}

SFoo foo1;
SFoo* foo2 = malloc(SFoo); // Compiler is smart enough to know
foo1.function();
foo2.function(); // Same syntax

No default constructor. No default destructor. Each component must be
explicitly coded and executed in code if needed ... thereby documenting it
without obfuscation, and allowing a straight-forward merging of structures
through multiple inheritance. My opinion.

> The bottom line is that standard C cannot, and IMHO should not, cater to
> every obscure coding practice. A language can have:
> 1. mutable string literals;
> 2. immutable string literals; or
> 3. both, with distinct syntax.
>
> C has chosen option 2, and it has served us well. I would not strongly
> object to option 3, but I'm not convinced that it would be worth the
> extra complexity. You're welcome to push for option 1, but don't expect
> to succeed.

I don't expect to get anywhere trying to change anything in C. :-) It's why
I'm moving to my own language. I hit the GCC group a while back asking for
the self() extension, which allows recursion to the current function without
it being explicitly named or even explicitly populated with parameters. They
said it was not a good idea. I asked for something else (can't remember what)
and they said the same. So ... it was fuel for me to get started on my own.

:-)

Best regards,
Rick C. Hodgin




== 7 of 15 ==
Date: Tues, Jan 21 2014 4:50 am
From: "Rick C. Hodgin"


On Monday, January 20, 2014 5:53:19 PM UTC-5, glen herrmannsfeldt wrote:
> Seems to me that when most people do this, or at least when I do,
> I substitute the copy just before writing it out. You need a loop
> that goes through and writes out the lines, inside that loop copy
> each line to a line buffer, modify as appropriate, then write
> it out.
>
> [snip]
>
> Very little work to write.


Still requires that I write some code, and maintain some code, and have a function that leaves allocated memory blocks hanging around (inviting leaks unless I code to handle them all properly all of the time). It's more than "very little work" to do this when, in the alternative, the very definition of the thing you'd be copying in your example would be utilized in my example.

The compiler option removes all issues.

Best regards,
Rick C. Hodgin




== 8 of 15 ==
Date: Tues, Jan 21 2014 4:54 am
From: "Rick C. Hodgin"


On Monday, January 20, 2014 5:37:41 PM UTC-5, Seebs wrote:
> On 2014-01-20, Rick C. Hodgin <rick...n@gmail.com> wrote:
> > On Monday, January 20, 2014 3:31:34 PM UTC-5, Eric Sosman wrote:
> >> But that was long ago: The uniqueness guarantee (and any
> >> accompanying mutability) was rescinded by the original ANSI C
> >> Standard way back in 1989.
> > And I bet you could hear the thuds on the floor as many developers
> > screamed "WHAT!" and then passed out.
>
> I don't think so. Back in the late 80s, when I was just starting to
> learn C, I was aware that if you had two string literals, and one was
> the same characters as the tail end of the other, the compiler might
> use the same storage for both. It's really easy to obtain a modifiable
> string if I want one, so I don't expect literals to be modifiable, or
> indeed, even to occur in code or storage anywhere if they don't really
> have to.


When most people encounter something they are in "learning how it works"
mode. They read and study and come to understand the system. However,
some people look at things differently desiring to understand the philosophy
of why something works. This gives them a different perspective than the
user, as they are more akin to a type of author, desiring to peer into the
inner workings and perform mental optimizations upon the design.

In my experience there are about 20% authors and 80% users in the developer
community. That number falls somewhat to 5% to 10% authors and 90% to 95%
users in certain types of developer houses (more long-term maintenance of
established applications, rather than new shops which are writing new apps).

My personal experience. YMMV.

Best regards,
Rick C. Hodgin




== 9 of 15 ==
Date: Tues, Jan 21 2014 4:58 am
From: "Rick C. Hodgin"


On Monday, January 20, 2014 6:14:48 PM UTC-5, Seebs wrote:
> On 2014-01-20, Rick C. Hodgin <rick...n@gmail.com> wrote:
> > On Monday, January 20, 2014 2:10:40 PM UTC-5, glen herrmannsfeldt wrote:
> >> Oh, also, one of my favorite C features (Java also has), you
> >> can have the extra comma on the last line. Convenient for program
> >> generated text, though most likely in the standard as it allows
> >> for easy preprocessor conditionals.
> > See, and I think that such an "allowance" is patently absurd and should
> > not be a part of any language. :-)
>
> Why? It's really convenient as a way to eliminate a gratuitous special
> case.


Why do we have "void function(void)" when "function()" would work sufficiently at that level in a source file? It's explicitly so we convey that no mistake was given as by accidentally leaving out some parameters. We declare void to indicate "I purposefully intended to leave this empty, there are no return variables, there are no parameters," and so on.

It's the same here. "Oh, another comma ... was the developer finished? Was there supposed to be more? What is missing? What was left out? Please ... I need answers. I'm left hanging in a state of confusion that is disrupting my soul. Whatever do I do?"

Nobody needs that kind of stress in their life. :-)

Best regards,
Rick C. Hodgin




== 10 of 15 ==
Date: Tues, Jan 21 2014 5:58 am
From: Eric Sosman


On 1/21/2014 6:57 AM, Rick C. Hodgin wrote:
> On Monday, January 20, 2014 4:32:04 PM UTC-5, Eric Sosman wrote:
>>[...]
>>>> Quoth the Rationale:
>>>> "String literals are not required to be modifiable. This
>>>> specification allows implementations to share copies of
>>>> strings with identical text, to place string literals in
>>>> [...] Those members of the C89 Committee who insisted that
>>>> string literals should be modifiable were content to have
>>>> this practice designated a common extension [...]"
>>> The word "common" being used very loosely there. LOL! :-)
>> See Appendix J.
>
> Appendix J of what?

Sorry; since you've been suggesting changes to the C language,
I supposed without justification that you were familiar with its
defining document. The appendix mentioned is in "ISO/IEC 9899:2011
Programming Language C," and is entitled "Portability Issues." The
relevant part is "J.5 Common Extensions," and the clause describing
the particular matter that upsets you is "J.5.5 Writeable String
Literals."

--
Eric Sosman
esosman@comcast-dot-net.invalid




== 11 of 15 ==
Date: Tues, Jan 21 2014 6:48 am
From: James Kuyper


On 01/21/2014 06:57 AM, Rick C. Hodgin wrote:
> On Monday, January 20, 2014 4:32:04 PM UTC-5, Eric Sosman wrote:
>> On 1/20/2014 3:42 PM, Rick C. Hodgin wrote:
>>>> But that was long ago: The uniqueness guarantee (and any
>>>> accompanying mutability) was rescinded by the original ANSI C
>>>> Standard way back in 1989.
>>
>>> And I bet you could hear the thuds on the floor as many developers
>>> screamed "WHAT!" and then passed out.

I doubt it - having lived through that period, I don't remember anyone
objecting to that decision. The biggest objections I've seen have been
in the other direction: string literals should have the type "const
char[n]", as they do in C++. As a result, they would automatically
convert to "const char*" in most contexts. If that were the case, most
code that accidentally tries to write to them would be a constraint
violation, requiring a diagnostic, which would make it a bit easier to
write correct code.

>> Did you miss the part about "Those members ... were content?"
>
> Not at all. I presumed "those members" involved in the ANSI authorizing were a small number, power-seeking representatives of the entire C language developer base of us "little people," while the much larger group (developers who were coding in C in general) contained many developers, and it was many of them who screamed "WHAT!" and then passed out.

"Those members" refers to the people on the committee "who insisted that
string literals should be modifiable". You paint an amazingly nasty
picture of those who agreed with your point of view on this issue.

The ANSI committee includes both people who implement C and people who
use C. I'm not sure exactly how many of each were present at, but I
believe that the implementors were actually less numerous, they
certainly were not in absolute control of the proceedings.
--
James Kuyper




== 12 of 15 ==
Date: Tues, Jan 21 2014 7:01 am
From: James Kuyper


On 01/20/2014 09:10 AM, Aleksandar Kuktin wrote:
> On Mon, 20 Jan 2014 04:53:33 -0800, Rick C. Hodgin wrote:
>
>> My current solution to do something along these lines during
>> initialization:
>> char* sourceCode[] =
>> {
>> "if (foo[9999] == 0) {\r\n",
>> " // Do something\r\n",
>> "} else if (foo[9999] == 1) {\r\n",
>> " // Do something else\r\n",
>> "} else {\r\n",
>> " // Do some other things\r\n", "}",
>> null
>> };
>>
>> int i, len;
>> char* ptr;
>> for (i = 0; list[i] != null; i++)
>> {
>> len = strlen(list[i]) + 1;
>> ptr = (char*)malloc(len); memcpy(ptr, list[0], len);
>> list[0] = ptr;
>> }
>
> And what, exactly, is wrong with the basic principle of this approach?
>
> I personally would have done something like this:
> char *read_only[] = { "Rick", "Jane", "Marc", 0 };
> char **read_write;
>
> char **init_readwrite(char **readonly) {
> unsigned int i, count;
> char **readwrite;
>
> for (count=0, i=0; readonly[i]; i++) {
> count++;
> }
> readwrite = malloc(count * sizeof(*readwrite));
> /* no check */
> return memcpy(read_write, read_only, count * sizeof(*readwrite));
> }
>
> read_write = init_readwrite(read_only);
>
> ...And then you operate on read_write and ignore read_only.

read_only is an array of pointers; the things that the pointers point at
are not modifiable. It should therefore, for safety, have been declared
as "const char*[]".

You allocate enough space to copy over all of the pointers to
read_write. Then you do copy them over. The new pointers in read_write
still point at the same locations as the ones in read_only; those
locations still cannot be safely written to, so nothing has been gained
by the copy. It is therefore incorrectly named.

That's why you need to create a deep copy, as in Rick's code. It copies
the strings themselves to memory that it guaranteed writable.
--
James Kuyper




== 13 of 15 ==
Date: Tues, Jan 21 2014 8:09 am
From: James Kuyper


On 01/20/2014 10:40 AM, Rick C. Hodgin wrote:
> On Monday, January 20, 2014 9:10:24 AM UTC-5, Aleksandar Kuktin wrote:
>> I personally would have done something like this:
>> char *read_only[] = { "Rick", "Jane", "Marc", 0 };
>> char **read_write;
>>
>> char **init_readwrite(char **readonly) {
>> unsigned int i, count;
>> char **readwrite;
>>
>> for (count=0, i=0; readonly[i]; i++) {
>> count++;
>> }
>> readwrite = malloc(count * sizeof(*readwrite));
>> /* no check */
>> return memcpy(read_write, read_only, count * sizeof(*readwrite));
>> }
>> read_write = init_readwrite(read_only);
>>
>> ...And then you operate on read_write and ignore read_only.
>
> I have not gone through this deeply or tried it in code, but I'm
thinking the theory of this solution would not work in all cases (and
that this particular implementation also will not work).
>
> Since each read_only[] pointer is to a constant string, and the
compiler creates the entry in read-only memory, it could optimize and
allow lines like "red" and "fred" to be mapped to the same four byte
area, one pointing to "f" and one pointing to "r" after "f". ...

That is quite true, but precisely because it is a statement about
pointers, it's not actually relevant.

> ... So making a
bulk copy would not copy all things properly in all cases.

This code just copies the pointers themselves, not the objects that they
point to, so the fact that the objects could be overlapping is not a
problem. The fact that it only copies the pointers IS a problem.

It would be possible to do this with a bulk copy only if there were some
way to ensure that all of the strings were stored in adjacent pieces of
memory:

char *read_only =
"if (something[9999])\r\n\0"
"{\r\n\0"
" // Do something\r\n\0"
"} else {\r\n\0"
" // Do something else\r\n\0"
"}";

Read that line carefully. Instead of having six separate string
literals, it has only a single string literal, containing six separate
non-overlapping strings, the first five terminated by explicit null
characters. This is done by the "magic" of string literal concatenation:
two consecutive string literals separated only by white space are
automatically merged into a single string.
You could do a bulk copy of those string literals, but the tricky part
would be figuring out how much space is needed. sizeof(read_only) gives
the size of the pointer. strlen(read_only) gives the length of the first
string, so neither is suitable. You'd have to iterate over all six
strings to find their total length, and you'll have to count them
manually, there's no way to use C constructs to determine that length
for you.

Much simpler would be the following:

char read_write[] =
"if (something[9999])\r\n\0"
"{\r\n\0"
" // Do something\r\n\0"
"} else {\r\n\0"
" // Do something else\r\n\0"
"}";

// Count the strings
int strings=0;
for(char *ptr = read_write; ptr < read_write + sizeof read_write;
ptr++)
if(*ptr = '\0')
strings++;

// Set up an array of pointers to the strings.
char **rw_ptrs = malloc(strings * sizeof *rw_ptrs);
if(rw_ptrs)
{
char *ptr = read_write;
for(int str = 0; str < strings; str++)
{
rw_ptrs[str] = ptr;
while(*ptr++); // move past end of string
}
}
--
James Kuyper




== 14 of 15 ==
Date: Tues, Jan 21 2014 8:17 am
From: James Kuyper


On 01/20/2014 12:39 PM, Rick C. Hodgin wrote:
> On Monday, January 20, 2014 11:32:10 AM UTC-5, Keith Thompson wrote:
>> "Rick C. Hodgin" <rick...n@gmail.com> writes:
...
>>> char* sourceCode[] =
>>> {
>>> "if (foo[9999]) {\r\n",
>>> " // Do something\r\n",
>>> "} else {\r\n",
>>> " // Do something else\r\n",
>>> "}\r\n"
>>> };
>>
>> This isn't relevant to your question, but why do you have explicit
>> "\r\n" line endings? If your program reads and/or writes the
>> source code in text mode (or if you're on a UNIX-like system),
>> line endings are marked by a single '\n' character, regardless of
>> the format used by the operating system.
>
> To be consistent with the source file input I'm processing. Without using both \r and \n it gives warnings when opening the files that the line endings are not consistent.

Do you open the input file and the output file in binary mode or text
mode? If you opened both in text mode, that shouldn't be happening,
unless you're reading an input file that has line endings that are
inconsistent with the conventions for your platform (for instance,
reading a file following Dos/Windows conventions on a Unix-like system).
--
James Kuyper




== 15 of 15 ==
Date: Tues, Jan 21 2014 8:28 am
From: "Rick C. Hodgin"


On Tuesday, January 21, 2014 11:17:33 AM UTC-5, James Kuyper wrote:
> On 01/20/2014 12:39 PM, Rick C. Hodgin wrote:
> >> This isn't relevant to your question, but why do you have explicit
> >> "\r\n" line endings? If your program reads and/or writes the
> >> source code in text mode (or if you're on a UNIX-like system),
> >> line endings are marked by a single '\n' character, regardless of
> >> the format used by the operating system.
> > To be consistent with the source file input I'm processing. Without
> > using both \r and \n it gives warnings when opening the files that the
> > line endings are not consistent.
>
> Do you open the input file and the output file in binary mode or text
> mode? If you opened both in text mode, that shouldn't be happening,
> unless you're reading an input file that has line endings that are
> inconsistent with the conventions for your platform (for instance,
> reading a file following Dos/Windows conventions on a Unix-like system).

Quoted as Mr. Miyagi speaking, "Binary. Always open binary." :-)

It is code for a Windows system and it uses two character line endings.

Best regards,
Rick C. Hodgin





==============================================================================
TOPIC: The Beauties of Islam
http://groups.google.com/group/comp.lang.c/t/3dd0812854727916?hl=en
==============================================================================

== 1 of 2 ==
Date: Mon, Jan 20 2014 4:06 pm
From: jacob navia


Le 20/01/2014 22:35, Melzzzzz a �crit :
> God can't create another God

great!

I didn't thought about that one!

:-)




== 2 of 2 ==
Date: Mon, Jan 20 2014 8:35 pm
From: Asaf Las


On Monday, January 20, 2014 11:35:07 PM UTC+2, Melzzzzz wrote:
> On Mon, 20 Jan 2014 22:27:50 +0100
> God can't create another God because what is created is not God by
> definition...
> Go not to the elves for counsel, for they will say both yes and no.
> -- J.R.R. Tolkien

But one compiler can create another one.





==============================================================================
TOPIC: Crazy but valid C...
http://groups.google.com/group/comp.lang.c/t/184fe3b933cf3175?hl=en
==============================================================================

== 1 of 3 ==
Date: Tues, Jan 21 2014 12:12 am
From: umesh.kalappa0@gmail.com


Hi All,

Below code is that valid C Construct for the functions call .

int test()
{
printf("test\n");
}

int main()
{
(***(int(****)(void))test)();
}

Thanks for the inputs
~Umesh





== 2 of 3 ==
Date: Tues, Jan 21 2014 12:32 am
From: Xavier Roche


On 01/21/2014 09:12 AM, umesh.kalappa0@gmail.com wrote:
> Below code is that valid C Construct for the functions call .
> (***(int(****)(void))test)();

(valid, but does not build with -Werror and proper warnings due to
strict aliasing issues)

This is due to the "A declaration of a parameter as "function returning
type" shall be adjusted to "pointer to function returning type"" rule,
and the obscure 6.3.2.1 4: �A function designator is an expression that
has function type. Except when it is the operand of the sizeof operator,
the _Alignof operator, or the unary & operator, a function designator
with type �function returning type� is converted to an expression that
has type �pointer to function returning type�

The wording is anything but clear, but unless I missed something, it
basically means that & and * yield the same pointer location for functions.





== 3 of 3 ==
Date: Tues, Jan 21 2014 3:57 am
From: Ben Bacarisse


umesh.kalappa0@gmail.com writes:

> Below code is that valid C Construct for the functions call .
>
> int test()
> {
> printf("test\n");
> }
>
> int main()
> {
> (***(int(****)(void))test)();
> }

No not valid. Tidied up and simplified to show the problem:

#include <stdio.h>

int test(void) { printf("test\n"); }

int main(void)
{
(*(int(**)(void))test)();
}

The type int(*)(void) is a function pointer type. The type
int(**)(void) is an object pointer type. The conversion is not defined
to be meaningful, and de-referencing the resulting pointer is almost
certainly going to go horribly wrong. Doing that multiple times just
makes the matter worse.

What does your compiler say about it? If it is silent -- ask for more
warnings. For gcc, -pedantic disables GNU extensions and makes gcc
report this problem.

--
Ben.





==============================================================================
TOPIC: Black magic, or insanity?
http://groups.google.com/group/comp.lang.c/t/ef5c82b8c8bd554c?hl=en
==============================================================================

== 1 of 6 ==
Date: Tues, Jan 21 2014 4:33 am
From: Robbie Brown


I've been reviewing what I've learned about pointers.

I thought I'd do a few tests just to consolidate what I thought I'd
learned and frankly .. I'm dumfounded.

int main(int argc, char *argv[]){

//declare a pointer to int
int *ip;

//print ... what exactly, prints 'nil'
printf("ip is %p\n", ip);
//dereference the pointer, seg fault
printf("*ip is %d\n", *ip);

}

the output is what I expected

ip is (nil)
Segmentation fault (core dumped)

I then add the following statement after the last printf

int *ip2;

compile and exec and get the same output

ip is (nil)
Segmentation fault (core dumped)

Now then, the next bit is a total head****

If I modify the last statement so that it reads

int *ip2 = NULL;

so the code is now

int main(int argc, char *argv[]){

//declare a pointer to int
int *ip;

//print ... what exactly, prints 'nil'
printf("ip is %p\n", ip);
//dereference the pointer, seg fault
printf("*ip is %d\n", *ip);

int *ip2 = NULL;

}

then compile and exec I get the following

ip is 0x7fff0dfeb230
*ip is 1

WTF!!! ... how does initalizing ip2 to NULL cause the
previous code to now display ... something.

Is this for real?
I mean seriously, this is just ... what

I have no idea

Dazed and confused.


--
rob




== 2 of 6 ==
Date: Tues, Jan 21 2014 5:47 am
From: Zoltan Kocsi


On Tue, 21 Jan 2014 12:33:12 +0000
Robbie Brown <dac@nomail.invalid> wrote:

> I've been reviewing what I've learned about pointers.
>
> I thought I'd do a few tests just to consolidate what I thought I'd
> learned and frankly .. I'm dumfounded.
>
> int main(int argc, char *argv[]){
>
> //declare a pointer to int
> int *ip;
>
> //print ... what exactly, prints 'nil'
> printf("ip is %p\n", ip);
> //dereference the pointer, seg fault
> printf("*ip is %d\n", *ip);
>
> }
>
> the output is what I expected
>
> ip is (nil)
> Segmentation fault (core dumped)

Your expectation is completely wrong. The fact that ip is nil is due to
luck. You do not initialise it. Automatic variables (i.e. ones defined
inside a function without the 'static' keyword) are *not* initialised
by the compiler. Whatever junk is on the stack, that's the initial
value. If your compiler does any optimisation, then it's not even
the stack. Most likely ip was allocated in a register, which the start
code (which executes before your main() enters) happened to set to 0.

> [ snip ]
> WTF!!! ... how does initalizing ip2 to NULL cause the
> previous code to now display ... something.

Chances are, ip was now allocated in a different register, due to the
need of allocating space for ip2. The new register contained a valid
address.

Since you have not initialised the pointers and they were not in the
BSS, you could expect nothing, absolutely nothing about their values.

Any decent compiler should have given you a warning about the
uninitialised nature of ip. Also note that even zeroing the BSS is a
hosted environment thing, many embedded systems do not initialise the
memory before starting main() at all.

Zoltan
--
Zoltán Kócsi
Bendor Research Pty. Ltd.





== 3 of 6 ==
Date: Tues, Jan 21 2014 6:09 am
From: Ben Bacarisse


Robbie Brown <dac@nomail.invalid> writes:

> I've been reviewing what I've learned about pointers.
>
> I thought I'd do a few tests just to consolidate what I thought I'd
> learned and frankly .. I'm dumfounded.

You just need to re-adjust your expectations. All of your examples have
what C calls undefined behaviour. The language standard does not say
what should happen, so compilers can do pretty much what they like.
Having any expectation at all is going to lead to puzzlement.

If, on the other hand, you want to know what is actually going on, then
just look at the generated code, but keep in mind that this will tell
you about one version of one compiler with one set of command-line flags
on one system at some particular time. You probably won't learn much of
use.

<snip>
--
Ben.




== 4 of 6 ==
Date: Tues, Jan 21 2014 6:14 am
From: Robbie Brown


On 21/01/14 13:47, Zoltan Kocsi wrote:
> On Tue, 21 Jan 2014 12:33:12 +0000
> Robbie Brown <dac@nomail.invalid> wrote:
>
>> I've been reviewing what I've learned about pointers.

<snip>

> Any decent compiler should have given you a warning about the
> uninitialised nature of ip.

Hmm, I'm using gcc version 4.6.3 ... is this a 'decent compiler'

gcc -std=gnu99 -Wall pointers.c -g -o pointers
gives no warnings about uninitialised anything.

I hear what you are saying though and have taken it on board.

Thanks for your time

--
rob




== 5 of 6 ==
Date: Tues, Jan 21 2014 6:19 am
From: Robbie Brown


On 21/01/14 14:09, Ben Bacarisse wrote:
> Robbie Brown <dac@nomail.invalid> writes:
>
>> I've been reviewing what I've learned about pointers.
>>
>> I thought I'd do a few tests just to consolidate what I thought I'd
>> learned and frankly .. I'm dumfounded.
>
> You just need to re-adjust your expectations. All of your examples have
> what C calls undefined behaviour. The language standard does not say
> what should happen, so compilers can do pretty much what they like.
> Having any expectation at all is going to lead to puzzlement.

I'm discovering this, fascinating stuff.

Thanks


--
rob




== 6 of 6 ==
Date: Tues, Jan 21 2014 6:43 am
From: Eric Sosman


On 1/21/2014 9:14 AM, Robbie Brown wrote:
> On 21/01/14 13:47, Zoltan Kocsi wrote:
>> On Tue, 21 Jan 2014 12:33:12 +0000
>> Robbie Brown <dac@nomail.invalid> wrote:
>>
>>> I've been reviewing what I've learned about pointers.
>
> <snip>
>
>> Any decent compiler should have given you a warning about the
>> uninitialised nature of ip.
>
> Hmm, I'm using gcc version 4.6.3 ... is this a 'decent compiler'
>
> gcc -std=gnu99 -Wall pointers.c -g -o pointers
> gives no warnings about uninitialised anything.

Strange. Even a much older (4.4.1) gcc gives me

foo.c: In function 'main':
foo.c:7: warning: implicit declaration of function 'printf'
foo.c:7: warning: incompatible implicit declaration of built-in
function 'printf'
foo.c:7: warning: 'ip' is used uninitialized in this function

A truly ancient (3.4.4) version emits only the `printf' warning,
but if invoked with optimization at -O1 or higher it also squawks
"warning: 'ip' might be used uninitialized in this function" (note
"might be" rather than "is"; this could be a different warning).

Wild guess: The detection of uninitialized uses depends on data
developed while optimizing, and the default optimization level when
no -Ox is specified varies from one gcc version to another. Try
adding -O1 or -O2 (or even -O3) to your command line, to see if
the compiler will offer more commentary.

--
Eric Sosman
esosman@comcast-dot-net.invalid




==============================================================================

You received this message because you are subscribed to the Google Groups "comp.lang.c"
group.

To post to this group, visit http://groups.google.com/group/comp.lang.c?hl=en

To unsubscribe from this group, send email to comp.lang.c+unsubscribe@googlegroups.com

To change the way you get mail from this group, visit:
http://groups.google.com/group/comp.lang.c/subscribe?hl=en

To report abuse, send email explaining the problem to abuse@googlegroups.com

==============================================================================
Google Groups: http://groups.google.com/?hl=en

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home


Real Estate