Error braces around scalar initializer

I have look-up-table as defined below and I'm making use of GCC. When I compile I get warnings as warning: braces around scalar initializer What does this warning mean? How should I initialize th...

I have look-up-table as defined below and I’m making use of GCC. When I compile I get warnings as

warning: braces around scalar initializer

What does this warning mean? How should I initialize this LUT? Am I making a mistake in initializing this structures?

Help!!


typedef struct TECH
{

    float velocity1, velocity2;
    float temp;
    float measure;

    int id;
    float storage[64];

}TECH;

struct TECH lut_model_1[2] = {{{296.001465},
        {74.216972},
        {2.025908},
        {1.516384},
        {1},
        {0.001746,
        0.000256, 0.006216, 0.005249, -0.001668, -0.001377, 0.009865, 0.010454, -0.000288, -0.005853, 0.010584, 0.015440, 0.000465, -0.000602, 0.004330, 0.005700, 0.017120,
        0.233015, 0.034154, 0.244022, 0.007644, 0.385683, 0.042960, 0.406633, -0.007811, 0.346931, 0.040123, 0.387361, 0.007030, 0.225309, 0.017897, 0.241024, 0.003700,
        0.103601, 0.060748, 0.121059, -0.045041, 0.076974, 0.070647, 0.148810, -0.022399, 0.074007, 0.054797, 0.141794, 0.010376, 0.052482, 0.045013, 0.078443, -0.019940,
        -0.057353, 0.044285, 0.066622, -0.058232, -0.093817, 0.064753, 0.126611, -0.008286, -0.085634, 0.029582, 0.140443, 0.009189, -0.052974, 0.036057, 0.087536}},

        {{309.270569},
        {74.520226},
        {2.088673},
        {1.595730},
        {1},
        {-0.003261,
        0.001452, 0.006673, 0.007092, 0.001020, 0.002904, 0.009037, 0.009587, -0.001494, 0.000296, 0.009327, 0.010013, -0.000301, -0.002727, 0.005875, 0.008888, -0.016850,
        0.231185, 0.029758, 0.241629, 0.009411, 0.382748, 0.057553, 0.407984, -0.019496, 0.393691, 0.045355, 0.411033, -0.019787, 0.185746, 0.027101, 0.216863, 0.010189,
        0.050463, 0.041380, 0.059462, 0.009747, 0.093188, 0.089831, 0.132579, -0.049612, 0.058789, 0.075130, 0.122026, -0.022185, 0.017041, 0.035450, 0.074255, -0.002068,
        -0.061219, 0.040752, 0.087084, -0.013021, -0.106098, 0.066566, 0.140099, -0.041966, -0.073433, 0.055231, 0.125908, -0.003481, -0.050690, 0.017257, 0.085251}}};

  1. 02-27-2008


    #1

    Osiris990 is offline


    Registered User


    error: braces around scalar initializer…

    The following snippet encompasses lines 4-56 in my code:

    Code:

    	record tmpKnowledgeBase[] = {
    		{"REPETITION T1**"},
    		LINK_SPECIAL,
    		{
    			"Why are you repeating yourself?",
    			"I heard you the first time.",
    			"This conversation is starting to bore me.",
    			"Don't you have anything else to say?"
    		},
    		{"REPETITION T2**"},
    		LINK_SPECIAL,
    		{
    			"Yes, I know. You already said that.",
    			"Didn't you already say that?",
    			"I'm getting the impression you're repeating yourself."
    		},
    		{"BOT DONT UNDERSTAND**"},
    		LINK_SPECIAL,
    		{
    			"What are you talking about?.",
    			"I'm not sure I understand what you mean...",
    			"Huh?"
    		},
    		{"NULL INPUT**"},
    		LINK_SPECIAL,
    		{
    			"What the heck is that supposed to mean?",
    			"At least take the time to say SOMETHING.",
    			"Talking requires TWO people, you know."
    		},
    		{"NULL INPUT REPETITION**"},
    		LINK_SPECIAL,
    		{
    			"...",
    			"Wow, that's really annoying. Stop it.",
    			"What's wrong with you?",
    			"This isn't funny - it's just stupid."
    		},
    		{"HELLO", "HI"},
    		LINK_OR,
    		{
    			"Hey there!",
    			"Hello.",
    			"Hiya!"
    		},
    		{"WHAT", "YOUR", "NAME"},
    		LINK_AND,
    		{
    			"My name is "+botName+"!",
    			"Does it really matter?",
    			botName+", at your service."
    		}
    	};

    Here are the declarations for structs record and keywords:

    Code:

    typedef struct {
    	std::string keyset[TURNERBOT_MAX_KEYWORDS];
    	int linkType;
    } keywords;
    
    typedef struct {
    	keywords keys;
    	std::string response[TURNERBOT_MAX_RESP];
    } record;

    Now, this looks fine to ME, but… I’m not that great a C++. I’m getting the following error when I try to compile:

    Code:

    /home/shane/TurnerBot/src/bot.cpp: In member function 'void TurnerBot::generateKnowledgeBase()':
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'std::string'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'int'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'std::string'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'std::string'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'int'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'std::string'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'std::string'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'int'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'std::string'
    /home/shane/TurnerBot/src/bot.cpp:56: error: braces around scalar initializer for type 'std::string'

    Can somebody please tell me what this is talking about and how I can fix it? =/


  2. 02-27-2008


    #2

    Dave_Sinkula is offline


    Just Lurking

    Dave_Sinkula's Avatar


    I think I ran into this once before. Although a single string literal initializer may be optionally enclosed in braces…

    Code:

    const char text[] = {"initializer"};

    …I don’t believe this recurses to members of an aggregate. I believe the fix is to write them as

    Code:

    const char text[] = "initializer";

    [edit]Looks up and sees it’s C++.
    Either that or there’s using the string constructor for these values.

    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*


  3. 02-27-2008


    #3

    CornedBee is offline


    Cat without Hat

    CornedBee's Avatar


    Your brace placement is wrong. The way you have it, the compiler thinks that {«REPETITION T1**»} is the initializer for a complete record struct.

    Should be

    Code:

    record tmpKnowledgeBase[] = {
    	{
    		{
    			{"REPETITION T1**"},
    			LINK_SPECIAL
    		},
    		{
    			"Why are you repeating yourself?",
    			"I heard you the first time.",
    			"This conversation is starting to bore me.",
    			"Don't you have anything else to say?"
    		}
    	},
    // ...

    All the buzzt!
    CornedBee

    «There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code.»
    — Flon’s Law



Description


Will Wray



2018-12-21 18:10:33 UTC

Note: This is a C++ specific issue (not C). All versions since C++11.

    int a[1]{{0}}; // GCC error - should be warning

GCC:   error: braces around scalar initializer for type 'int'
Clang: warning: braces around scalar initializer [-Wbraced-scalar-init]
Intel: warning #1119: extra braces are nonstandard
MSVC:  no warning (with Wall)

    "I'm frankly stunned that GCC rejects."
        Quote from a Clang dev (cfe-dev thread linked below).

Same error on initializing a scalar member of an aggregate:

    struct S { int i; };
    S s{{0}}; // GCC error - should be warning

Or, on initializing an array-of-scalar aggregate member:

    struct SA { int n[1]; };
    SA sa{{{0}}}; // GCC error - should be warning

A different but related bug (non-SFINAE-error) was just fixed on Clang trunk.
The discussion thread is here:
http://clang-developers.42468.n3.nabble.com/braces-around-scalar-initializer-warning-should-be-error-td4063311.html
The Clang fix commit is here, with test code applicable to this GCC bug:
https://github.com/llvm-mirror/clang/commit/3410781dffff51e89751a2494bd8dfe7e7d83541

Here's a compiler explorer link with the test code:
https://gcc.godbolt.org/z/8HCba4

test code listing
=================

  using valid = int&;
  using invalid = float&;

  template<typename T> valid braces1(decltype(T{0})*);
  template<typename T> invalid braces1(...);

  template<typename T> valid braces2(decltype(T{{0}})*);
  template<typename T> invalid braces2(...);

  template<typename T> valid braces3(decltype(T{{{0}}})*);
  template<typename T> invalid braces3(...);

  valid   scalar_1_brace = braces1<int>(0);
  invalid scalar_2_brace = braces2<int>(0);
  invalid scalar_3_brace = braces3<int>(0);

//int a[1]{{0}}; // GCC error - should be warning

  valid   array_scalar_1_brace = braces1<int[1]>(0);
  valid   array_scalar_2_brace = braces2<int[1]>(0); // GCC error
  invalid array_scalar_3_brace = braces3<int[1]>(0);

  struct SS { int n; };
//SS ss{{0}}; // GCC error - should be warning

  valid   struct_scalar_1_brace = braces1<SS>(0);
  valid   struct_scalar_2_brace = braces2<SS>(0);  // GCC error
  invalid struct_scalar_3_brace = braces3<SS>(0);

  struct SAS { int n[1]; };
//SAS sas{{{0}}}; // GCC error - should be warning

  valid struct_array_scalar_1_brace = braces1<SAS>(0);
  valid struct_array_scalar_2_brace = braces2<SAS>(0);
  valid struct_array_scalar_3_brace = braces3<SAS>(0); // GCC error


Comment 1


Will Wray



2018-12-28 22:33:37 UTC

This bug is straightforward to confirm.
Compile this snippet (-std=c++11 / 14 / 17 / 2a):

    struct S { int i; };
    S s{{0}};

Gives       error: braces around scalar initializer for type 'int'
Should be a warning

(Or, follow the provided compiler explorer link to the test code
 which includes two more failing cases - array and array member.)

The standard is clear that scalar brace init should be accepted:

C++14 [dcl.init.aggr]/2 says:
    "Each member is copy-initialized from the corresponding initializer-clause.
[...] [ Note: If an initializer-clause is itself an initializer list, the
member is list-initialized, which will result in a recursive application of the
rules in this section if the member is an aggregate.  — end note ]"

C++14 [dcl.init.list]/3.5:
    "Otherwise, if the initializer list has a single element of type E and
either T is not a reference type or its referenced type is reference-related to
E, the object or reference is initialized from that element;"


Some historical links leading up to the wording fixes:

DR 155. Brace initializer for scalar
     Explains it was a C/C++ incompatibility pre-11 and points to:

DR 632. Brace-enclosed initializer for scalar member of aggregate
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#632
      "The initializer-list proposal will resolve this issue..."

As stated, it was resolved in C++11 by Initializer Lists:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm

1501. Nested braces in list-initialization
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1501

DR1467 List-initialization of aggregate from same-type object
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467
  Submitter: Jason Merrill     Date: 2012-02-06
 [Moved to DR at the November, 2014 meeting.]

Please CONFIRM this bug.


Comment 3


Jonathan Wakely



2019-01-07 15:19:01 UTC

The relevant code is:

      /* It is invalid to initialize a non-aggregate type with a
	 brace-enclosed initializer before C++0x.
	 We need to check for BRACE_ENCLOSED_INITIALIZER_P here because
	 of g++.old-deja/g++.mike/p7626.C: a pointer-to-member constant is
	 a CONSTRUCTOR (with a record type).  */
      if (TREE_CODE (stripped_init) == CONSTRUCTOR
	  /* Don't complain about a capture-init.  */
	  && !CONSTRUCTOR_IS_DIRECT_INIT (stripped_init)
	  && BRACE_ENCLOSED_INITIALIZER_P (stripped_init))  /* p7626.C */
	{
	  if (SCALAR_TYPE_P (type))
	    {
	      if (cxx_dialect < cxx11
		  /* Isn't value-initialization.  */
		  || CONSTRUCTOR_NELTS (stripped_init) > 0)
		{
		  if (complain & tf_error)
		    error ("braces around scalar initializer for type %qT",
			   type);
		  init = error_mark_node;
		}
	    }

The condition means we give an error for any braced-init-list in C++98, and for a non-empty braced-init-list in later dialects . But the latter condition is wrong, it should allow a single element (and presumably more than one element will be rejected as an invalid initializer anyway).

I'm not even sure we should warn about this.


Comment 4


Jonathan Wakely



2019-01-07 15:42:37 UTC

Changing it to a warning, like so:

--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6054,15 +6054,19 @@ reshape_init_r (tree type, reshape_iter *d, bool first_initializer_p,
        {
          if (SCALAR_TYPE_P (type))
            {
-             if (cxx_dialect < cxx11
-                 /* Isn't value-initialization.  */
-                 || CONSTRUCTOR_NELTS (stripped_init) > 0)
+             if (cxx_dialect < cxx11)
                {
                  if (complain & tf_error)
                    error ("braces around scalar initializer for type %qT",
                           type);
                  init = error_mark_node;
                }
+             /* No warning for value-initialization.  */
+             else if (CONSTRUCTOR_NELTS (stripped_init) > 0)
+               {
+                 warning (0, "braces around scalar initializer for type %qT",
+                          type);
+               }
            }
          else
            maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);


Causes the test code in comment 0 to issue lots of warnings (as expected) but also a new error:

88572.cc:14:40: error: cannot bind non-const lvalue reference of type 'invalid' {aka 'float&'} to an rvalue of type 'float'
   14 |   invalid scalar_2_brace = braces2<int>(0);
      |                            ~~~~~~~~~~~~^~~

Which means that int{{0}} is now accepted, so my patch isn't right.


Comment 5


Will Wray



2019-01-07 15:50:18 UTC

Right; the patch should only apply within aggregate initialization -
arrays and aggregate structures - as the initialization of actual scalars
was already correct.

I'll take a look now (as I meaning to fix my enum patch this week too).


Comment 6


Jonathan Wakely



2019-01-07 16:02:21 UTC

I don't think reshape_init_r has the context of the type that contains the object being initialized, so might need an extra parameter passed to it.


Comment 7


Will Wray



2019-01-07 16:47:16 UTC

I guess that the bug persisted so long *because* of the status quo;
portable code had to delete extra braces to silence warnings or to compile
i.e. the warning on Clang served the purpose of promoting portability to GCC.

So, as to whether it should be a warning; I think not, but...
for practical portability reasons, it probably should be left as a warning
at least until some epoch like C++2a where both GCC & Clang could remove
the warning under the -std=c++2a flag. Make sense?

FYI My use case is counting aggregate members, similar to fields_count
in boost/pfr 'magic_get', but extended to support array members:

https://github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/fields_count.hpp

That code initializes an aggregate T from an index_sequence I... as
    T{ ubiq{I}... }   (where ubiq is a 'convert to anything' type)

To support 'skipping' arrays, you want to initialize the aggregate as
    T{ {ubiq{I}}...}

but, for scalar members, this is what currently fails on GCC / warns on Clang.

Another reason that the bug persisted is the general confusion around braces
and uniform initialization - this fix will give a generic, uniform, way to
initialize the leading members of an aggregate.

I wonder if the extra braces should have additional benefits like not allowing
narrowing conversions. My limited experiments (on Clang) show no difference.


Comment 8


Jonathan Wakely



2019-01-07 16:52:39 UTC

(In reply to Will Wray from comment #7)
> So, as to whether it should be a warning; I think not, but...
> for practical portability reasons, it probably should be left as a warning
> at least until some epoch like C++2a where both GCC & Clang could remove
> the warning under the -std=c++2a flag. Make sense?

No, I don't think so. I don't see why the warning should be given for C++11 but not C++2a when the code is valid for both.

I think it should be accepted without a warning. I'd be more inclined to say it should be accepted in C++98 with a -pedantic warning, rather than give a warning for C++11.

> I wonder if the extra braces should have additional benefits like not
> allowing
> narrowing conversions. My limited experiments (on Clang) show no difference.

The outermost braces already mean it's a context that doesn't allow narrowing, so the additional inner braces make no difference.


Comment 9


Will Wray



2019-01-07 22:15:43 UTC

The patch below seems to work as far as I've tested - please review.

It looks like the bool first_initializer_p argument to reshape_init_r
gives the context that is needed, according to the function comment;

/* ...
   FIRST_INITIALIZER_P is true if this is the first initializer of the
   outermost CONSTRUCTOR node.  */

If I read this right then this bool arg is true for scalar init and
false when initializing a scalar member of an aggregate (class or array).

The patch below rejects
int ii{{0}};

--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -6054,16 +6054,19 @@ reshape_init_r (tree type, reshape_iter
 	{
 	  if (SCALAR_TYPE_P (type))
 	    {
-	      if (cxx_dialect < cxx11
-		  /* Isn't value-initialization.  */
-		  || CONSTRUCTOR_NELTS (stripped_init) > 0)
+	      if (cxx_dialect < cxx11 || first_initializer_p)
 		{
 		  if (complain & tf_error)
 		    error ("braces around scalar initializer for type %qT",
 			   type);
 		  init = error_mark_node;
 		}
-	    }
+              else if (CONSTRUCTOR_NELTS (stripped_init) > 0)
+		{
+ 		  warning (0, "braces around scalar initializer for type %qT",
+ 		           type);
+ 		}
+            }
 	  else
 	    maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
 	}


Comment 10


Will Wray



2019-01-07 22:24:47 UTC

Re: warnings; I certainly prefer to have this accepted with no warning
(i.e. remove the 'else if' warning in the patch above).
Saves having to disable the warning in GCC, as I have to do in Clang.


Comment 11


Jonathan Wakely



2019-01-07 23:57:01 UTC

(In reply to Will Wray from comment #9)
> The patch below seems to work as far as I've tested - please review.
> 
> It looks like the bool first_initializer_p argument to reshape_init_r
> gives the context that is needed, according to the function comment;
> 
> /* ...
>    FIRST_INITIALIZER_P is true if this is the first initializer of the
>    outermost CONSTRUCTOR node.  */
> 
> If I read this right then this bool arg is true for scalar init and
> false when initializing a scalar member of an aggregate (class or array).

I understood it to mean something like {{1}, 2} is the first,
                                        ^^^
but apparently not. The patch works for me, but I can't review it properly.


Comment 12


Will Wray



2019-01-08 19:51:47 UTC

On further investigation the logic of using first_initializer_p looks correct.

The comment on reshape_init suggests that it wasn't intended for scalar init:

 /* Undo the brace-elision allowed by [dcl.init.aggr] in a
    brace-enclosed aggregate initializer.

    INIT is the CONSTRUCTOR containing the list of initializers describing
    a brace-enclosed initializer for an entity of the indicated aggregate TYPE.

In fact, reshape_init is used more broadly to error-check braced-init-list -
- the first substantive case is direct enum init, a scalar init special-case.
Perhaps the general scalar case should be dealt with here at the top level.
Instead the recursive call to reshape_init_r is done next
setting first_initializer_p to true - the only place it is set true
(the true value will be forwarded to reshape_init_class for class type).

So, for a scalar init, the tree type passed to reshape_init is SCALAR_TYPE_P.
This is passed down to reshape_init_r with first_initializer_p set true.

Entering reshape_init_r we have

  if (first_initializer_p && !CP_AGGREGATE_TYPE_P (type)
      && has_designator_problem (d, complain))
    return error_mark_node;

Here, first_initializer_p && !CP_AGGREGATE_TYPE_P (type) covers scalar init
(and other non-aggregate init).

Arriving at our block, we also enter a context requiring a single-initializer

  /* A non-aggregate type is always initialized with a single
     initializer.  */
  if (!CP_AGGREGATE_TYPE_P (type))

and then further filter down to CONSTRUCTOR with BRACE_ENCLOSED_INITIALIZER_P
and, specifically of SCALAR_TYPE_P

      if (TREE_CODE (stripped_init) == CONSTRUCTOR
	  /* Don't complain about a capture-init.  */
	  && !CONSTRUCTOR_IS_DIRECT_INIT (stripped_init)
	  && BRACE_ENCLOSED_INITIALIZER_P (stripped_init))  /* p7626.C */
	{
	  if (SCALAR_TYPE_P (type))


> I understood it to mean something like {{1}, 2} is the first,
>                                         ^^^

Me too, but taking "outermost CONSTRUCTOR node" to mean the actual outer type
here (first_initializer_p==true) and with only a single scalar initializer:

  like scalar_type{{1}}    not {           {1} }
                   ^^^          scalar_type^^^

So, I've convinced myself that my patch follows the existing logic.
It'd be good to get review from someone not suffering from confirmation bias.


Comment 13


Will Wray



2019-01-09 16:07:56 UTC

Re-reviewing, I notice that the patch I posted in comment #9
now rejects nested empty-brace scalar init:

  int i{{}};

which was previously accepted. So we'll need a decision on this too.

Clang rejects with -pedantic-errors or warns otherwise:
   pedantic error / warning: too many braces around scalar initializer

MSVC rejects:
   error: 'initializing': cannot convert from 'initializer list' to 'int'
   note: Too many braces around initializer for 'int'

I reckon that Clang is right to reject under -pedantic, else accept and warn

This Quora post comes to a similar conclusion:

https://www.quora.com/Is-double-braced-scalar-initialization-allowed-by-the-C-standard-int-x

>accepting {{}} for int seems like a harmless language extension.


Comment 14


Will Wray



2019-02-04 22:57:17 UTC

I intend to submit a patch, or two patches, for these scalar braced init issues:

Case 1: GCC rejects braced-init of scalars in aggregates. It should accept.
Case 2: GCC accepts empty braced-init of scalars (comment 13). It should reject.

Fixing case 2 has the potential to break code.
Such broken code is already rejected by Clang and MSVC.
It seems unlikely that there will be any examples of this in the wild.

Both case 1 and case 2 are fixed by the patch in comment 9.
The patch needs to be updated to give a warning only when appropriate.

I plan to submit a single patch to fix both issues.
A more cautious approach would be to submit 2 separate patches.
Please speak now if you'd prefer to see 2 patches.


Comment 15


Will Wray



2019-02-12 22:36:57 UTC

Created attachment 45683 [details]
Proposed patch including updated tests

Accept braces around scalar initializer within aggregate init,
previously rejected; this patch accepts without a warning.

Reject braced empty-brace value-initialization of scalar variable
previously accepted.

Maintain C++98 rejection of scalar braced-init.

See Bug 88572 for details, standards links and extra test code.

Log:
	PR c++/88572
	* decl.c (reshape_init_r): Remove condition that was incorrectly
        rejecting braces around scalar initializer within aggregate init. 
        Produce no warning. Replace with condition rejecting braced-init
        of scalar variable, including empty-brace value-initialization
        that was being incorrectly accepted. Produce same error for both.

	PR c++/88572
	* g++.dg/cpp0x/initlist69.C: Update 2 tests; changed error, OK.
	* g++.dg/cpp1z/direct-enum-init1.C: Update 3 tests; changed error.
	* g++.dg/init/brace1.C: Update 1 test; error only on c++98. Add
          1 test with one more set of braces; error on too many braces.
	* g++.dg/init/brace2.C: Add 1 test; empty-brace scalar init fail.
        * g++.dg/init/union2.C: Update 1 test; error only on c++98. Add
          1 test with one more set of braces; error on too many braces.
	* g++.dg/warn/Wbraces2.C: Update 3 test; 1 error only on c++98.
          2 now give invalid conversion instead of braces error on >98.


Comment 16


Will Wray



2019-02-20 17:18:34 UTC

Created attachment 45778 [details]
Updated patch addressing review comments

(Updated Change Log entry for decl.c)

Log:
	PR c++/88572
	* decl.c (reshape_init_r): Remove condition that was incorrectly
        rejecting braces around scalar initializer within aggregate init. 
        Produce no warning. Add a conditional block rejecting braced-init
        of scalar variable, including empty-brace value-initialization
        that was being incorrectly accepted.


Comment 17


Jason Merrill



2019-02-20 18:51:03 UTC

Author: jason
Date: Wed Feb 20 18:50:32 2019
New Revision: 269045

URL: https://gcc.gnu.org/viewcvs?rev=269045&root=gcc&view=rev
Log:
	PR c++/88572 - wrong handling of braces on scalar init.

	* decl.c (reshape_init_r): Allow braces around scalar initializer
	within aggregate init.  Reject double braced-init of scalar
	variable.

Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/decl.c
    trunk/gcc/testsuite/g++.dg/cpp0x/initlist69.C
    trunk/gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C
    trunk/gcc/testsuite/g++.dg/init/brace1.C
    trunk/gcc/testsuite/g++.dg/init/brace2.C
    trunk/gcc/testsuite/g++.dg/init/union2.C
    trunk/gcc/testsuite/g++.dg/warn/Wbraces2.C


Comment 18


Jason Merrill



2019-02-21 18:17:24 UTC

Fixed in GCC 9.


Comment 19


Marek Polacek



2020-06-10 13:34:57 UTC

*** Bug 95559 has been marked as a duplicate of this bug. ***

у меня есть таблица поиска, как определено ниже, и я использую GCC. Когда я компилирую, я получаю предупреждения как

warning: braces around scalar initializer

что означает это предупреждение? Как инициализировать этот LUT? Я делаю ошибку, инициализируя эти структуры?

помогите!!


typedef struct TECH
{

    float velocity1, velocity2;
    float temp;
    float measure;

    int id;
    float storage[64];

}TECH;

struct TECH lut_model_1[2] = {{{296.001465},
        {74.216972},
        {2.025908},
        {1.516384},
        {1},
        {0.001746,
        0.000256, 0.006216, 0.005249, -0.001668, -0.001377, 0.009865, 0.010454, -0.000288, -0.005853, 0.010584, 0.015440, 0.000465, -0.000602, 0.004330, 0.005700, 0.017120,
        0.233015, 0.034154, 0.244022, 0.007644, 0.385683, 0.042960, 0.406633, -0.007811, 0.346931, 0.040123, 0.387361, 0.007030, 0.225309, 0.017897, 0.241024, 0.003700,
        0.103601, 0.060748, 0.121059, -0.045041, 0.076974, 0.070647, 0.148810, -0.022399, 0.074007, 0.054797, 0.141794, 0.010376, 0.052482, 0.045013, 0.078443, -0.019940,
        -0.057353, 0.044285, 0.066622, -0.058232, -0.093817, 0.064753, 0.126611, -0.008286, -0.085634, 0.029582, 0.140443, 0.009189, -0.052974, 0.036057, 0.087536}},

        {{309.270569},
        {74.520226},
        {2.088673},
        {1.595730},
        {1},
        {-0.003261,
        0.001452, 0.006673, 0.007092, 0.001020, 0.002904, 0.009037, 0.009587, -0.001494, 0.000296, 0.009327, 0.010013, -0.000301, -0.002727, 0.005875, 0.008888, -0.016850,
        0.231185, 0.029758, 0.241629, 0.009411, 0.382748, 0.057553, 0.407984, -0.019496, 0.393691, 0.045355, 0.411033, -0.019787, 0.185746, 0.027101, 0.216863, 0.010189,
        0.050463, 0.041380, 0.059462, 0.009747, 0.093188, 0.089831, 0.132579, -0.049612, 0.058789, 0.075130, 0.122026, -0.022185, 0.017041, 0.035450, 0.074255, -0.002068,
        -0.061219, 0.040752, 0.087084, -0.013021, -0.106098, 0.066566, 0.140099, -0.041966, -0.073433, 0.055231, 0.125908, -0.003481, -0.050690, 0.017257, 0.085251}}};

5 ответов


вы должны удалить скобки: { и } вокруг одного значения.

struct TECH lut_model_1[2] = {{296.001465,
        74.216972,
        2.025908,
        1.516384,
        1,
        {0.001746,
        0.000256, 0.006216, 0.005249, -0.001668, -0.001377, 0.009865, 0.010454, -0.000288, -0.005853, 0.010584, 0.015440, 0.000465, -0.000602, 0.004330, 0.005700, 0.017120,
        0.233015, 0.034154, 0.244022, 0.007644, 0.385683, 0.042960, 0.406633, -0.007811, 0.346931, 0.040123, 0.387361, 0.007030, 0.225309, 0.017897, 0.241024, 0.003700,
        0.103601, 0.060748, 0.121059, -0.045041, 0.076974, 0.070647, 0.148810, -0.022399, 0.074007, 0.054797, 0.141794, 0.010376, 0.052482, 0.045013, 0.078443, -0.019940,
        -0.057353, 0.044285, 0.066622, -0.058232, -0.093817, 0.064753, 0.126611, -0.008286, -0.085634, 0.029582, 0.140443, 0.009189, -0.052974, 0.036057, 0.087536}},

        {309.270569,
        74.520226,
        2.088673,
        1.595730,
        1,
        {-0.003261,
        0.001452, 0.006673, 0.007092, 0.001020, 0.002904, 0.009037, 0.009587, -0.001494, 0.000296, 0.009327, 0.010013, -0.000301, -0.002727, 0.005875, 0.008888, -0.016850,
        0.231185, 0.029758, 0.241629, 0.009411, 0.382748, 0.057553, 0.407984, -0.019496, 0.393691, 0.045355, 0.411033, -0.019787, 0.185746, 0.027101, 0.216863, 0.010189,
        0.050463, 0.041380, 0.059462, 0.009747, 0.093188, 0.089831, 0.132579, -0.049612, 0.058789, 0.075130, 0.122026, -0.022185, 0.017041, 0.035450, 0.074255, -0.002068,
        -0.061219, 0.040752, 0.087084, -0.013021, -0.106098, 0.066566, 0.140099, -0.041966, -0.073433, 0.055231, 0.125908, -0.003481, -0.050690, 0.017257, 0.085251}}};

не даст никакого предупреждения.


в языке C совершенно законно использовать дополнительные фигурные скобки при инициализации скалярного значения, как в

int x = { 5 };

даже если вы обычно не увидеть это в реальном коде. В вашем случае вы делаете то же самое, за исключением того, что в вашем случае скалярное значение является членом большей совокупности.

GCC генерирует предупреждения для такого кода. Он считает, что возможно, что вы написали что-то, что вы не собирались писать, так как брекеты большую часть времени используется для запуска многосоставного инициализатора для агрегата, а не автономного инициализатора для скаляра.

<rant>GCC определенно портит вещи своими предупреждениями о фигурных скобках в агрегатных инициализаторах. На языке C { 0 } всегда использовался в качестве идиоматического универсального нулевого инициализатора. По крайней мере!—2—> должен был быть освобожден от предупреждений, связанных с скобками, для его идиоматического значения.</rant>


это скалярный инициализатор:int foo = 3;
Это скалярный инициализатор с фигурными скобками вокруг него:int foo = {3};
Это инициализатор массива, который не является скалярным:int foo[] = {1, 2, 3};

в предупреждении говорится, что ваша структура имеет скалярные инициализаторы с фигурными скобками вокруг них:

typedef struct TECH
{

    float velocity1, velocity2;
...

struct TECH lut_model_1[2] = {{{296.001465},
    {74.216972},
...

ваш код будет работать, он просто имеет лишние скобки вокруг своих скалярных инициализаторов. Если вы вытащите фигурные скобки и отформатируете их немного более красиво (я бы поставил первый инициализатор его собственная линия) в этом не будет ничего предосудительного.


это означает, что вам не нужно ставить фигурные скобки в таких местах, как:

    {74.216972},

в принципе, все фигурные скобки, которые у вас есть, являются необязательными (кроме внешних), однако вы получите другое предупреждение за не охватывающие вложенные структуры в инициализаторе. В принципе, если вы не против предупреждения, поместите фигурные скобки только вокруг вложенных структур и массивов; если нет, используйте их для улучшения читаемости, как вам нравится.


вы инициализируете скалярные значения (velocity1, temp и т. д.), окружая их фигурными скобками, что не требуется.

попробуйте это:

struct TECH lut_model_1[2] = {{296.001465,
        74.216972,
        2.025908,
        1.516384,
        1,
        {0.001746,
        0.000256, 0.006216, 0.005249, -0.001668, -0.001377, 0.009865, 0.010454, -0.000288, -0.005853, 0.010584, 0.015440, 0.000465, -0.000602, 0.004330, 0.005700, 0.017120,
        0.233015, 0.034154, 0.244022, 0.007644, 0.385683, 0.042960, 0.406633, -0.007811, 0.346931, 0.040123, 0.387361, 0.007030, 0.225309, 0.017897, 0.241024, 0.003700,
        0.103601, 0.060748, 0.121059, -0.045041, 0.076974, 0.070647, 0.148810, -0.022399, 0.074007, 0.054797, 0.141794, 0.010376, 0.052482, 0.045013, 0.078443, -0.019940,
        -0.057353, 0.044285, 0.066622, -0.058232, -0.093817, 0.064753, 0.126611, -0.008286, -0.085634, 0.029582, 0.140443, 0.009189, -0.052974, 0.036057, 0.087536}},

        {309.270569,
        74.520226,
        2.088673,
        1.595730,
        1,
        {-0.003261,
        0.001452, 0.006673, 0.007092, 0.001020, 0.002904, 0.009037, 0.009587, -0.001494, 0.000296, 0.009327, 0.010013, -0.000301, -0.002727, 0.005875, 0.008888, -0.016850,
        0.231185, 0.029758, 0.241629, 0.009411, 0.382748, 0.057553, 0.407984, -0.019496, 0.393691, 0.045355, 0.411033, -0.019787, 0.185746, 0.027101, 0.216863, 0.010189,
        0.050463, 0.041380, 0.059462, 0.009747, 0.093188, 0.089831, 0.132579, -0.049612, 0.058789, 0.075130, 0.122026, -0.022185, 0.017041, 0.035450, 0.074255, -0.002068,
        -0.061219, 0.040752, 0.087084, -0.013021, -0.106098, 0.066566, 0.140099, -0.041966, -0.073433, 0.055231, 0.125908, -0.003481, -0.050690, 0.017257, 0.085251}}};

У меня есть справочная таблица, как определено ниже, и я использую GCC. Когда я компилирую, я получаю предупреждения как

warning: braces around scalar initializer

Что означает это предупреждение? Как мне инициализировать эту LUT? Я делаю ошибку при инициализации этих структур?

Помощь!


typedef struct TECH
{

    float velocity1, velocity2;
    float temp;
    float measure;

    int id;
    float storage[64];

}TECH;

struct TECH lut_model_1[2] = {{{296.001465},
        {74.216972},
        {2.025908},
        {1.516384},
        {1},
        {0.001746,
        0.000256, 0.006216, 0.005249, -0.001668, -0.001377, 0.009865, 0.010454, -0.000288, -0.005853, 0.010584, 0.015440, 0.000465, -0.000602, 0.004330, 0.005700, 0.017120,
        0.233015, 0.034154, 0.244022, 0.007644, 0.385683, 0.042960, 0.406633, -0.007811, 0.346931, 0.040123, 0.387361, 0.007030, 0.225309, 0.017897, 0.241024, 0.003700,
        0.103601, 0.060748, 0.121059, -0.045041, 0.076974, 0.070647, 0.148810, -0.022399, 0.074007, 0.054797, 0.141794, 0.010376, 0.052482, 0.045013, 0.078443, -0.019940,
        -0.057353, 0.044285, 0.066622, -0.058232, -0.093817, 0.064753, 0.126611, -0.008286, -0.085634, 0.029582, 0.140443, 0.009189, -0.052974, 0.036057, 0.087536}},

        {{309.270569},
        {74.520226},
        {2.088673},
        {1.595730},
        {1},
        {-0.003261,
        0.001452, 0.006673, 0.007092, 0.001020, 0.002904, 0.009037, 0.009587, -0.001494, 0.000296, 0.009327, 0.010013, -0.000301, -0.002727, 0.005875, 0.008888, -0.016850,
        0.231185, 0.029758, 0.241629, 0.009411, 0.382748, 0.057553, 0.407984, -0.019496, 0.393691, 0.045355, 0.411033, -0.019787, 0.185746, 0.027101, 0.216863, 0.010189,
        0.050463, 0.041380, 0.059462, 0.009747, 0.093188, 0.089831, 0.132579, -0.049612, 0.058789, 0.075130, 0.122026, -0.022185, 0.017041, 0.035450, 0.074255, -0.002068,
        -0.061219, 0.040752, 0.087084, -0.013021, -0.106098, 0.066566, 0.140099, -0.041966, -0.073433, 0.055231, 0.125908, -0.003481, -0.050690, 0.017257, 0.085251}}};

OrmaJever

9 / 9 / 0

Регистрация: 10.11.2011

Сообщений: 241

1

27.01.2013, 19:44. Показов 5689. Ответов 13

Метки нет (Все метки)


Вобщем то был обычный масив строк

C
1
2
3
const char *someName[] = {
   "str1", "str2", "str3", ... "strN"
}

Но масив этот большой, а в нём приходится искать определёное слово много раз, поэтому решил поделить этот масив на двухмерный с групировкой по первой букве.

C
1
2
3
4
5
6
7
8
9
10
11
12
const char *someName[] = {
  { // A
     "Astr1", "Astr2", "Astr3", ... "AstrN"
  },
  { // B
     "Bstr1", "Bstr2", "Bstr3", ... "BstrN"
  },
  ....
  { // Z
     "Zstr1", "Zstr2", "Zstr3", ... "ZstrN"
  },
}

Строк на каждую букву разное количество (если что)
Но вот теперь я схватываю кучу warning’ов

Код

warning: braces around scalar initializer
warning: (near initialization for 'someName[0]')
warning: excess elements in scalar initializer
warning: (near initialization for 'someName[0]')
warning: excess elements in scalar initializer
.........

и так по каждому слову. Я понимаю что нужно как-то обьявить масив по другому, но как только не пробовал, ошибки не пропадают. Читал на эту тему stackoverflow но там примеры с интами и пользовательскими структурами, но указатели на char как я понимаю немного запутанее.

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



lowercase

213 / 202 / 85

Регистрация: 09.05.2012

Сообщений: 494

27.01.2013, 21:38

2

Цитата
Сообщение от OrmaJever
Посмотреть сообщение

но указатели на char как я понимаю немного запутанее

не то чтобы уж очень так. просто нужно чуток выделить память, а потом и чуток освободить.

примерно так:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>
 
#define STR_SIZE 128
#define MATRIX_M 10
#define MATRIX_N 8
 
int main() {
    /* выделение памяти сначала выделяем память
            под указатели на строки матрицы(именно матрицы,
            а не те стоки в которых символы) */.
    char*** string_matrix = (char***)calloc(MATRIX_M, sizeof(char**));
    int i, j;
    for(i = 0; i < MATRIX_M; i++){
        /* теперь выделям память под указатели
            на елементы матрицы, то есть указатели
            на строки символов */
        string_matrix[i] = (char**)calloc(MATRIX_N, sizeof(char*));
        for(j = 0; j < MATRIX_N; j++){
            // теперь собственно выделяем память под сами строки символов
            string_matrix[i][j] = (char*)calloc(STR_SIZE, sizeof(char));
        }
    }
    
    /* доступ точно такой же как и к обычному масиву */
    i = 5; j = 6;
    fgets(string_matrix[i][j], STR_SIZE, stdin);
    printf("Entreed string: %sn", string_matrix[i][j]);
    
    
    /* и на конец освобождение памяти. освобождение 
        выполняет в обратном к выделению порядке */
    for(i = 0; i < MATRIX_M; i++)   {
 
        for(j = 0; j < MATRIX_N; j++){
 
            free(string_matrix[i][j]);
        }
        free(string_matrix[i]);
    }
    free(string_matrix);
    return 0;
}



1



OrmaJever

9 / 9 / 0

Регистрация: 10.11.2011

Сообщений: 241

27.01.2013, 21:56

 [ТС]

3

ойойой, не, так не годись. А как синтаксически верно в рантайме можно динамически получить имя переменой?Тоесть тогда разобью на несколько простоых масивов типа

C
1
2
3
const char *someNameA[] = {"Astr1", "Astr2", "Astr3", ... "AstrN"}
const char *someNameB[] = {"Bstr1", "Bstr2", "Bstr3", ... "BstrN"}
// и т.д

и нужно будет собрать имя масива взависимости от буквы, тоесть someName+(*word-0x61) (*word-0x61) — это типо некая буква вычисляемая в рантайме.

Или может предложите лучший вариант? Просто вариант с выделением памяти мне не очень нравится.



0



213 / 202 / 85

Регистрация: 09.05.2012

Сообщений: 494

27.01.2013, 22:04

4

а именованные константы? загнать индексы под имя. не?

Добавлено через 7 минут

Цитата
Сообщение от OrmaJever
Посмотреть сообщение

Просто вариант с выделением памяти мне не очень нравится.

ну в любом случаее память будет выделятся. просто сдесь она выделяется динамически(на этапе выполнения)



0



9 / 9 / 0

Регистрация: 10.11.2011

Сообщений: 241

27.01.2013, 22:11

 [ТС]

5

Цитата
Сообщение от lowercase
Посмотреть сообщение

а именованные константы? загнать индексы под имя. не?

Добавлено через 7 минут

ну в любом случаее память будет выделятся. просто сдесь она выделяется динамически(на этапе выполнения)

Можно пример? Ато я не понял что это и как)

Добавлено через 2 минуты

Цитата
Сообщение от lowercase
Посмотреть сообщение

а именованные константы? загнать индексы под имя. не?

Добавлено через 7 минут

ну в любом случаее память будет выделятся. просто сдесь она выделяется динамически(на этапе выполнения)

Ну я и имел это в виду, просто не хочу ввидеть у себя в коде видеть вложеные циклы, кучу выделений памяти из-за какой то мелочи которая может выполнится сама.



0



lowercase

213 / 202 / 85

Регистрация: 09.05.2012

Сообщений: 494

27.01.2013, 22:19

6

обычный define, ну например вот так:

C
1
2
3
4
5
6
7
8
#define SOMENAME_A 0
#define SOMENAME_B 1
/* и тд */
int main(){
   /* гдето выше выделели память, теперь используем */
   printf("%sn", string_matrix[SOMENAME_B][8]);
   return 0;
}

Добавлено через 2 минуты
ну можно в общем и выделить просто память под масивы строк точно так же как я показал выше.
а я просто сделал масив масивов строк

Добавлено через 2 минуты

Цитата
Сообщение от OrmaJever
Посмотреть сообщение

Ну я и имел это в виду, просто не хочу ввидеть у себя в коде видеть вложеные циклы, кучу выделений памяти из-за какой то мелочи которая может выполнится сама.

ну тогда может ктото другой подскажет вам чтото. а так в общем варнинг это не ошибка. с ним программа работать будет тоже.



0



OrmaJever

9 / 9 / 0

Регистрация: 10.11.2011

Сообщений: 241

27.01.2013, 22:31

 [ТС]

7

Цитата
Сообщение от lowercase
Посмотреть сообщение

ну можно в общем и выделить просто память под масивы строк точно так же как я показал выше.
а я просто сделал масив масивов строк

ага, значит вы меня не совсем поняли. Обычный одномерный масив который содержит все слова компилируется нормально и работает так же

C
1
2
3
const char *someName[] = {
   "str1", "str2", "str3", ... "strN"
}

А те самый ошибки появляются только при создании двухмерного масива как написал в первом посте. В том то и суть что под одномерный масив я не выделял память, поэтмоу немного удивился что под двухмерный уже нужны такие изменения.
Что касается примера с константами, то да, если использовать string_matrix как двухмерный масив то проблем нету, но вить я немогу его создать без ошибок. На том же stackoverflow спокойно без *alloc писали примеры двухмерных масивов int’ов и собственых структур, но с указателями на char как я не крутил так не выходило!
Так всётаки может возможно создать двухмерный масив статических строк без выделения памяти?

Добавлено через 1 минуту
Вот пример структур http://stackoverflow.com/quest… nitializer
а вот числа http://stackoverflow.com/quest… ay-of-ints



0



lowercase

213 / 202 / 85

Регистрация: 09.05.2012

Сообщений: 494

28.01.2013, 00:40

8

тьфу! что же я раньше не додумался! двухмерный масив строк — это же трехмерный масив символов

вот оно ваше(и мое вместе с вами ) щастье:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
 
#define STR_SIZE 128
#define MATRIX_M 2
#define MATRIX_N 2
 
char string_matrix[MATRIX_M][MATRIX_N][STR_SIZE] = {
    { "armagedon", "dep breath" },
    { "lowercase", "sun shine" }
};
 
int main() {
    int i, j;
    for(i = 0; i < MATRIX_M; i++){
        for(j = 0; j < MATRIX_N; j++){
            printf("%sn", string_matrix[i][j]);
        }
    }
    return 0;
}

ни каких предупреждений и ошибок, все компилируется и выполняется на ура. и скрин есть тому подтверждение

Миниатюры

Строки: warning: (near initialization for 'someName[0]')
 



1



OrmaJever

9 / 9 / 0

Регистрация: 10.11.2011

Сообщений: 241

28.01.2013, 01:17

 [ТС]

9

но ведь есть один нюанс который я описал в первом посте

Цитата
Сообщение от OrmaJever
Посмотреть сообщение

Строк на каждую букву разное количество (если что)

Тоесть подмасивов будет 26 (буквы англ алфавита), но вот слов в каждом из них разное количество и слова эти разумеется тоже разного размера поэтому я не могу указать размер в двух последних скобках, а такой вариант не прокатывает

C
1
char string_matrix[26][][] = {

Код

error: array type has incomplete element type

А казалось бы задача то простейшая, слова статичны и заранее извесны… но это же си…

Добавлено через 1 минуту
Вариант с двойным указателем на масив

C
1
char **string_matrix[26] = {

Компилится но ошибки из первого поста остаются



0



lowercase

213 / 202 / 85

Регистрация: 09.05.2012

Сообщений: 494

28.01.2013, 01:25

10

стопачки.. а ведь вот так тоже скомпилировалось:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
 
#define MATRIX_M 2
#define MATRIX_N 2
 
char *string_matrix[MATRIX_M][MATRIX_N] = {
    { "armagedon", "dep breath" },
    { "lowercase", "sun shine" }
};
 
int main() {
    int i, j;
    for(i = 0; i < MATRIX_M; i++){
        for(j = 0; j < MATRIX_N; j++){
            printf("%sn", string_matrix[i][j]);
        }
    }
    return 0;
}

странно, я вроде с самого начала так пробовал и не получалось. черт его знает может где забыл чтото.

Добавлено через 1 минуту
так вы хотели?

Добавлено через 2 минуты
вот вам лог сборки если хотите убедится.

Кликните здесь для просмотра всего текста

«/usr/bin/make» -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .clean-conf
make[1]: Entering directory `/d/work/c/C____test’
rm -f -r build/Debug
rm -f dist/Debug/MinGW-Windows/c____test.exe
make[1]: Leaving directory `/d/work/c/C____test’

CLEAN SUCCESSFUL (total time: 2s)

«/usr/bin/make» -f nbproject/Makefile-Debug.mk QMAKE= SUBPROJECTS= .build-conf
make[1]: Entering directory `/d/work/c/C____test’
«/usr/bin/make» -f nbproject/Makefile-Debug.mk dist/Debug/MinGW-Windows/c____test.exe
make[2]: Entering directory `/d/work/c/C____test’
mkdir -p build/Debug/MinGW-Windows
rm -f build/Debug/MinGW-Windows/main.o.d
gcc.exe -c -g -MMD -MP -MF build/Debug/MinGW-Windows/main.o.d -o build/Debug/MinGW-Windows/main.o main.c
mkdir -p dist/Debug/MinGW-Windows
gcc.exe -o dist/Debug/MinGW-Windows/c____test build/Debug/MinGW-Windows/main.o
make[2]: Leaving directory `/d/work/c/C____test’
make[1]: Leaving directory `/d/work/c/C____test’

BUILD SUCCESSFUL (total time: 3s)



1



9 / 9 / 0

Регистрация: 10.11.2011

Сообщений: 241

28.01.2013, 01:32

 [ТС]

11

У меня так тоже компилируется если я задам во вторых скобках количество слов, но ведь оно в разных масивах разное, не плохо ли это? Например
в string_matrix[0] — 100 слов
в string_matrix[1] — 230 слов
в string_matrix[2] — 50 слов
я указал во вторых скобках 230 (что бы хватило всем), получается в первом масиве памяти выделится куда больше чем надо, и в трейтем тоже. Нормально ли это?



0



lowercase

213 / 202 / 85

Регистрация: 09.05.2012

Сообщений: 494

28.01.2013, 01:42

12

а колличество слов известно на этапе компиляции или определяется в рантайме?

Добавлено через 2 минуты
тьфу туплю. вы же делаете инициализацию

Добавлено через 5 минут
можно еще сделать так

C
1
2
3
4
5
6
#define MATRIX_N 2
 
char *string_matrix[][MATRIX_N] = {
    { "armagedon", "dep breath" },
    { "lowercase", "sun shine" }
};

но это будет не то. тут колличество строк матрицы, а не строк символов низвенстно. то есть здесь MATRIX_N задает колличество строк на строку марицы.

по моему вам остается только указатели и выделение памяти. или указание памяти с запасом при инициализации



0



9 / 9 / 0

Регистрация: 10.11.2011

Сообщений: 241

28.01.2013, 01:54

 [ТС]

13

Цитата
Сообщение от lowercase
Посмотреть сообщение

а колличество слов известно на этапе компиляции или определяется в рантайме?

Конешно, И количество и сами слова известны при компиляции, это просто статичный перечень слов по которым в рантайме будет ити поиск, что бы каждый раз не проходить все слова (их более 5тыс) решил разделить их по первым буквам, вот собствено и тема об этом.
Ну чтож, воспользовался избыточным выделением, хрен с ней с этой памятью.



0



lowercase

213 / 202 / 85

Регистрация: 09.05.2012

Сообщений: 494

28.01.2013, 02:09

14

Цитата
Сообщение от OrmaJever
Посмотреть сообщение

Ну чтож, воспользовался избыточным выделением, хрен с ней с этой памятью.

погодите вешать нос вот вам моя последняя отчаяная попытка помочь:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
 
char* some_words1[] = { "word0", "word1", "word2" };
char* some_words2[] = { "word0", "word1" };
char* some_words3[] = { "word0", "word1", "word2", "word3"};
 
char **string_matrix[] = {
    some_words1, some_words2, some_words3
};
 
int main() {
    printf("%sn", string_matrix[0][2]);
    printf("%sn", string_matrix[1][1]);
    printf("%sn", string_matrix[2][3]);
    return 0;
}

Миниатюры

Строки: warning: (near initialization for 'someName[0]')
 



1



Понравилась статья? Поделить с друзьями:
  • Error box tkinter
  • Error box shadow
  • Error boundary перевод
  • Error boundary react что это
  • Error boundary react typescript